db2b70378636d55de78a6b42fd898fe02c282be0
[reactos.git] / reactos / ntoskrnl / mm / section.c
1 /* $Id$
2 *
3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 *
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/section.c
22 * PURPOSE: Implements section objects
23 *
24 * PROGRAMMERS: Rex Jolliff
25 * David Welch
26 * Eric Kohl
27 * Emanuele Aliberti
28 * Eugene Ingerman
29 * Hartmut Birr
30 * Casper Hornstrup
31 * KJK::Hyperion
32 * Guido de Jong
33 * Ge van Geldorp
34 * Royce Mitchell III
35 * Filip Navara
36 * Aleksey Bragin
37 * Jason Filby
38 * Thomas Weidenmueller
39 * Gunnar Andre' Dalsnes
40 * Mike Nordell
41 * Alex Ionescu
42 * Gregor Anich
43 * Steven Edwards
44 * Herve Poussineau
45 */
46
47 /* INCLUDES *****************************************************************/
48
49 #include <ntoskrnl.h>
50 #define NDEBUG
51 #include <internal/debug.h>
52 #include <reactos/exeformat.h>
53
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
57 #endif
58
59
60 /* TYPES *********************************************************************/
61
62 typedef struct
63 {
64 PSECTION_OBJECT Section;
65 PMM_SECTION_SEGMENT Segment;
66 ULONG Offset;
67 BOOLEAN WasDirty;
68 BOOLEAN Private;
69 }
70 MM_SECTION_PAGEOUT_CONTEXT;
71
72 /* GLOBALS *******************************************************************/
73
74 POBJECT_TYPE MmSectionObjectType = NULL;
75
76 static GENERIC_MAPPING MmpSectionMapping = {
77 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
78 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
79 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
80 SECTION_ALL_ACCESS};
81
82 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
83 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
84 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
85 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
86 #define MAX_SHARE_COUNT 0x7FF
87 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
88 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
89 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
90
91 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
92 {
93 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
94 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
95 };
96
97 /* FUNCTIONS *****************************************************************/
98
99 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
100
101 /*
102 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
103 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
104 * RETURNS: Status of the wait.
105 */
106 static NTSTATUS
107 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
108 {
109 LARGE_INTEGER Timeout;
110 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
111
112 Timeout.QuadPart = -100000000LL; // 10 sec
113 #else
114
115 Timeout.QuadPart = -100000000; // 10 sec
116 #endif
117
118 return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
119 }
120
121
122 /*
123 * FUNCTION: Sets the page op completion event and releases the page op.
124 * ARGUMENTS: PMM_PAGEOP.
125 * RETURNS: In shorter time than it takes you to even read this
126 * description, so don't even think about geting a mug of coffee.
127 */
128 static void
129 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
130 {
131 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
132 MmReleasePageOp(PageOp);
133 }
134
135
136 /*
137 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
138 * ARGUMENTS: PFILE_OBJECT to wait for.
139 * RETURNS: Status of the wait.
140 */
141 static NTSTATUS
142 MmspWaitForFileLock(PFILE_OBJECT File)
143 {
144 return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
145 }
146
147
148 VOID
149 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
150 {
151 ULONG i;
152 if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
153 {
154 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
155 {
156 if (Segment->PageDirectory.PageTables[i] != NULL)
157 {
158 ExFreePool(Segment->PageDirectory.PageTables[i]);
159 }
160 }
161 }
162 }
163
164 VOID
165 NTAPI
166 MmFreeSectionSegments(PFILE_OBJECT FileObject)
167 {
168 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
169 {
170 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
171 PMM_SECTION_SEGMENT SectionSegments;
172 ULONG NrSegments;
173 ULONG i;
174
175 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
176 NrSegments = ImageSectionObject->NrSegments;
177 SectionSegments = ImageSectionObject->Segments;
178 for (i = 0; i < NrSegments; i++)
179 {
180 if (SectionSegments[i].ReferenceCount != 0)
181 {
182 DPRINT1("Image segment %d still referenced (was %d)\n", i,
183 SectionSegments[i].ReferenceCount);
184 KEBUGCHECK(0);
185 }
186 MmFreePageTablesSectionSegment(&SectionSegments[i]);
187 }
188 ExFreePool(ImageSectionObject->Segments);
189 ExFreePool(ImageSectionObject);
190 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
191 }
192 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
193 {
194 PMM_SECTION_SEGMENT Segment;
195
196 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
197 DataSectionObject;
198
199 if (Segment->ReferenceCount != 0)
200 {
201 DPRINT1("Data segment still referenced\n");
202 KEBUGCHECK(0);
203 }
204 MmFreePageTablesSectionSegment(Segment);
205 ExFreePool(Segment);
206 FileObject->SectionObjectPointer->DataSectionObject = NULL;
207 }
208 }
209
210 VOID
211 NTAPI
212 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
213 {
214 ExAcquireFastMutex(&Segment->Lock);
215 }
216
217 VOID
218 NTAPI
219 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
220 {
221 ExReleaseFastMutex(&Segment->Lock);
222 }
223
224 VOID
225 NTAPI
226 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
227 ULONG Offset,
228 ULONG Entry)
229 {
230 PSECTION_PAGE_TABLE Table;
231 ULONG DirectoryOffset;
232 ULONG TableOffset;
233
234 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
235 {
236 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
237 }
238 else
239 {
240 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
241 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
242 if (Table == NULL)
243 {
244 Table =
245 Segment->PageDirectory.PageTables[DirectoryOffset] =
246 ExAllocatePoolWithTag(PagedPool, sizeof(SECTION_PAGE_TABLE),
247 TAG_SECTION_PAGE_TABLE);
248 if (Table == NULL)
249 {
250 KEBUGCHECK(0);
251 }
252 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
253 DPRINT("Table %x\n", Table);
254 }
255 }
256 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
257 Table->Entry[TableOffset] = Entry;
258 }
259
260
261 ULONG
262 NTAPI
263 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
264 ULONG Offset)
265 {
266 PSECTION_PAGE_TABLE Table;
267 ULONG Entry;
268 ULONG DirectoryOffset;
269 ULONG TableOffset;
270
271 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
272
273 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
274 {
275 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
276 }
277 else
278 {
279 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
280 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
281 DPRINT("Table %x\n", Table);
282 if (Table == NULL)
283 {
284 return(0);
285 }
286 }
287 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
288 Entry = Table->Entry[TableOffset];
289 return(Entry);
290 }
291
292 VOID
293 NTAPI
294 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
295 ULONG Offset)
296 {
297 ULONG Entry;
298
299 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
300 if (Entry == 0)
301 {
302 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
303 KEBUGCHECK(0);
304 }
305 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
306 {
307 DPRINT1("Maximum share count reached\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 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
316 }
317
318 BOOLEAN
319 NTAPI
320 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
321 PMM_SECTION_SEGMENT Segment,
322 ULONG Offset,
323 BOOLEAN Dirty,
324 BOOLEAN PageOut)
325 {
326 ULONG Entry;
327 BOOLEAN IsDirectMapped = FALSE;
328
329 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
330 if (Entry == 0)
331 {
332 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
333 KEBUGCHECK(0);
334 }
335 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
336 {
337 DPRINT1("Zero share count for unshare\n");
338 KEBUGCHECK(0);
339 }
340 if (IS_SWAP_FROM_SSE(Entry))
341 {
342 KEBUGCHECK(0);
343 }
344 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
345 /*
346 * If we reducing the share count of this entry to zero then set the entry
347 * to zero and tell the cache the page is no longer mapped.
348 */
349 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
350 {
351 PFILE_OBJECT FileObject;
352 PBCB Bcb;
353 SWAPENTRY SavedSwapEntry;
354 PFN_TYPE Page;
355 BOOLEAN IsImageSection;
356 ULONG FileOffset;
357
358 FileOffset = Offset + Segment->FileOffset;
359
360 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
361
362 Page = PFN_FROM_SSE(Entry);
363 FileObject = Section->FileObject;
364 if (FileObject != NULL &&
365 !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
366 {
367
368 if ((FileOffset % PAGE_SIZE) == 0 &&
369 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
370 {
371 NTSTATUS Status;
372 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
373 IsDirectMapped = TRUE;
374 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
375 if (!NT_SUCCESS(Status))
376 {
377 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
378 KEBUGCHECK(0);
379 }
380 }
381 }
382
383 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
384 if (SavedSwapEntry == 0)
385 {
386 if (!PageOut &&
387 ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
388 (Segment->Characteristics & IMAGE_SCN_MEM_SHARED)))
389 {
390 /*
391 * FIXME:
392 * Try to page out this page and set the swap entry
393 * within the section segment. There exist no rmap entry
394 * for this page. The pager thread can't page out a
395 * page without a rmap entry.
396 */
397 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
398 }
399 else
400 {
401 MmSetPageEntrySectionSegment(Segment, Offset, 0);
402 if (!IsDirectMapped)
403 {
404 MmReleasePageMemoryConsumer(MC_USER, Page);
405 }
406 }
407 }
408 else
409 {
410 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
411 (Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
412 {
413 if (!PageOut)
414 {
415 if (Dirty)
416 {
417 /*
418 * FIXME:
419 * We hold all locks. Nobody can do something with the current
420 * process and the current segment (also not within an other process).
421 */
422 NTSTATUS Status;
423 Status = MmWriteToSwapPage(SavedSwapEntry, Page);
424 if (!NT_SUCCESS(Status))
425 {
426 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
427 KEBUGCHECK(0);
428 }
429 }
430 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
431 MmSetSavedSwapEntryPage(Page, 0);
432 }
433 MmReleasePageMemoryConsumer(MC_USER, Page);
434 }
435 else
436 {
437 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
438 KEBUGCHECK(0);
439 }
440 }
441 }
442 else
443 {
444 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
445 }
446 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
447 }
448
449 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
450 ULONG SegOffset)
451 {
452 if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
453 {
454 PBCB Bcb;
455 PCACHE_SEGMENT CacheSeg;
456 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
457 CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
458 if (CacheSeg)
459 {
460 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
461 return TRUE;
462 }
463 }
464 return FALSE;
465 }
466
467 NTSTATUS
468 NTAPI
469 MiReadPage(PMEMORY_AREA MemoryArea,
470 ULONG SegOffset,
471 PPFN_TYPE Page)
472 /*
473 * FUNCTION: Read a page for a section backed memory area.
474 * PARAMETERS:
475 * MemoryArea - Memory area to read the page for.
476 * Offset - Offset of the page to read.
477 * Page - Variable that receives a page contains the read data.
478 */
479 {
480 ULONG BaseOffset;
481 ULONG FileOffset;
482 PVOID BaseAddress;
483 BOOLEAN UptoDate;
484 PCACHE_SEGMENT CacheSeg;
485 PFILE_OBJECT FileObject;
486 NTSTATUS Status;
487 ULONG RawLength;
488 PBCB Bcb;
489 BOOLEAN IsImageSection;
490 ULONG Length;
491
492 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
493 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
494 RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
495 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
496 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
497
498 ASSERT(Bcb);
499
500 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
501
502 /*
503 * If the file system is letting us go directly to the cache and the
504 * memory area was mapped at an offset in the file which is page aligned
505 * then get the related cache segment.
506 */
507 if ((FileOffset % PAGE_SIZE) == 0 &&
508 (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
509 !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
510 {
511
512 /*
513 * Get the related cache segment; we use a lower level interface than
514 * filesystems do because it is safe for us to use an offset with a
515 * alignment less than the file system block size.
516 */
517 Status = CcRosGetCacheSegment(Bcb,
518 FileOffset,
519 &BaseOffset,
520 &BaseAddress,
521 &UptoDate,
522 &CacheSeg);
523 if (!NT_SUCCESS(Status))
524 {
525 return(Status);
526 }
527 if (!UptoDate)
528 {
529 /*
530 * If the cache segment isn't up to date then call the file
531 * system to read in the data.
532 */
533 Status = ReadCacheSegment(CacheSeg);
534 if (!NT_SUCCESS(Status))
535 {
536 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
537 return Status;
538 }
539 }
540 /*
541 * Retrieve the page from the cache segment that we actually want.
542 */
543 (*Page) = MmGetPhysicalAddress((char*)BaseAddress +
544 FileOffset - BaseOffset).QuadPart >> PAGE_SHIFT;
545
546 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
547 }
548 else
549 {
550 PVOID PageAddr;
551 ULONG CacheSegOffset;
552 /*
553 * Allocate a page, this is rather complicated by the possibility
554 * we might have to move other things out of memory
555 */
556 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
557 if (!NT_SUCCESS(Status))
558 {
559 return(Status);
560 }
561 Status = CcRosGetCacheSegment(Bcb,
562 FileOffset,
563 &BaseOffset,
564 &BaseAddress,
565 &UptoDate,
566 &CacheSeg);
567 if (!NT_SUCCESS(Status))
568 {
569 return(Status);
570 }
571 if (!UptoDate)
572 {
573 /*
574 * If the cache segment isn't up to date then call the file
575 * system to read in the data.
576 */
577 Status = ReadCacheSegment(CacheSeg);
578 if (!NT_SUCCESS(Status))
579 {
580 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
581 return Status;
582 }
583 }
584 PageAddr = MmCreateHyperspaceMapping(*Page);
585 CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
586 Length = RawLength - SegOffset;
587 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
588 {
589 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length);
590 }
591 else if (CacheSegOffset >= PAGE_SIZE)
592 {
593 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
594 }
595 else
596 {
597 memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
598 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
599 Status = CcRosGetCacheSegment(Bcb,
600 FileOffset + CacheSegOffset,
601 &BaseOffset,
602 &BaseAddress,
603 &UptoDate,
604 &CacheSeg);
605 if (!NT_SUCCESS(Status))
606 {
607 MmDeleteHyperspaceMapping(PageAddr);
608 return(Status);
609 }
610 if (!UptoDate)
611 {
612 /*
613 * If the cache segment isn't up to date then call the file
614 * system to read in the data.
615 */
616 Status = ReadCacheSegment(CacheSeg);
617 if (!NT_SUCCESS(Status))
618 {
619 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
620 MmDeleteHyperspaceMapping(PageAddr);
621 return Status;
622 }
623 }
624 if (Length < PAGE_SIZE)
625 {
626 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
627 }
628 else
629 {
630 memcpy((char*)PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
631 }
632 }
633 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
634 MmDeleteHyperspaceMapping(PageAddr);
635 }
636 return(STATUS_SUCCESS);
637 }
638
639 NTSTATUS
640 NTAPI
641 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
642 MEMORY_AREA* MemoryArea,
643 PVOID Address,
644 BOOLEAN Locked)
645 {
646 ULONG Offset;
647 PFN_TYPE Page;
648 NTSTATUS Status;
649 PVOID PAddress;
650 PSECTION_OBJECT Section;
651 PMM_SECTION_SEGMENT Segment;
652 ULONG Entry;
653 ULONG Entry1;
654 ULONG Attributes;
655 PMM_PAGEOP PageOp;
656 PMM_REGION Region;
657 BOOL HasSwapEntry;
658
659 /*
660 * There is a window between taking the page fault and locking the
661 * address space when another thread could load the page so we check
662 * that.
663 */
664 if (MmIsPagePresent(AddressSpace->Process, Address))
665 {
666 if (Locked)
667 {
668 MmLockPage(MmGetPfnForProcess(AddressSpace->Process, Address));
669 }
670 return(STATUS_SUCCESS);
671 }
672
673 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
674 Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
675 + MemoryArea->Data.SectionData.ViewOffset;
676
677 Segment = MemoryArea->Data.SectionData.Segment;
678 Section = MemoryArea->Data.SectionData.Section;
679 Region = MmFindRegion(MemoryArea->StartingAddress,
680 &MemoryArea->Data.SectionData.RegionListHead,
681 Address, NULL);
682 /*
683 * Lock the segment
684 */
685 MmLockSectionSegment(Segment);
686
687 /*
688 * Check if this page needs to be mapped COW
689 */
690 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
691 (Region->Protect == PAGE_READWRITE ||
692 Region->Protect == PAGE_EXECUTE_READWRITE))
693 {
694 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
695 }
696 else
697 {
698 Attributes = Region->Protect;
699 }
700
701 /*
702 * Get or create a page operation descriptor
703 */
704 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset, MM_PAGEOP_PAGEIN, FALSE);
705 if (PageOp == NULL)
706 {
707 DPRINT1("MmGetPageOp failed\n");
708 KEBUGCHECK(0);
709 }
710
711 /*
712 * Check if someone else is already handling this fault, if so wait
713 * for them
714 */
715 if (PageOp->Thread != PsGetCurrentThread())
716 {
717 MmUnlockSectionSegment(Segment);
718 MmUnlockAddressSpace(AddressSpace);
719 Status = MmspWaitForPageOpCompletionEvent(PageOp);
720 /*
721 * Check for various strange conditions
722 */
723 if (Status != STATUS_SUCCESS)
724 {
725 DPRINT1("Failed to wait for page op, status = %x\n", Status);
726 KEBUGCHECK(0);
727 }
728 if (PageOp->Status == STATUS_PENDING)
729 {
730 DPRINT1("Woke for page op before completion\n");
731 KEBUGCHECK(0);
732 }
733 MmLockAddressSpace(AddressSpace);
734 /*
735 * If this wasn't a pagein then restart the operation
736 */
737 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
738 {
739 MmspCompleteAndReleasePageOp(PageOp);
740 DPRINT("Address 0x%.8X\n", Address);
741 return(STATUS_MM_RESTART_OPERATION);
742 }
743
744 /*
745 * If the thread handling this fault has failed then we don't retry
746 */
747 if (!NT_SUCCESS(PageOp->Status))
748 {
749 Status = PageOp->Status;
750 MmspCompleteAndReleasePageOp(PageOp);
751 DPRINT("Address 0x%.8X\n", Address);
752 return(Status);
753 }
754 MmLockSectionSegment(Segment);
755 /*
756 * If the completed fault was for another address space then set the
757 * page in this one.
758 */
759 if (!MmIsPagePresent(AddressSpace->Process, Address))
760 {
761 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
762 HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
763
764 if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
765 {
766 /*
767 * The page was a private page in another or in our address space
768 */
769 MmUnlockSectionSegment(Segment);
770 MmspCompleteAndReleasePageOp(PageOp);
771 return(STATUS_MM_RESTART_OPERATION);
772 }
773
774 Page = PFN_FROM_SSE(Entry);
775
776 MmSharePageEntrySectionSegment(Segment, Offset);
777
778 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
779 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
780 */
781 Status = MmCreateVirtualMapping(AddressSpace->Process,
782 Address,
783 Attributes,
784 &Page,
785 1);
786 if (!NT_SUCCESS(Status))
787 {
788 DbgPrint("Unable to create virtual mapping\n");
789 KEBUGCHECK(0);
790 }
791 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
792 }
793 if (Locked)
794 {
795 MmLockPage(Page);
796 }
797 MmUnlockSectionSegment(Segment);
798 PageOp->Status = STATUS_SUCCESS;
799 MmspCompleteAndReleasePageOp(PageOp);
800 DPRINT("Address 0x%.8X\n", Address);
801 return(STATUS_SUCCESS);
802 }
803
804 HasSwapEntry = MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress);
805 if (HasSwapEntry)
806 {
807 /*
808 * Must be private page we have swapped out.
809 */
810 SWAPENTRY SwapEntry;
811
812 /*
813 * Sanity check
814 */
815 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
816 {
817 DPRINT1("Found a swaped out private page in a pagefile section.\n");
818 KEBUGCHECK(0);
819 }
820
821 MmUnlockSectionSegment(Segment);
822 MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
823
824 MmUnlockAddressSpace(AddressSpace);
825 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
826 if (!NT_SUCCESS(Status))
827 {
828 KEBUGCHECK(0);
829 }
830
831 Status = MmReadFromSwapPage(SwapEntry, Page);
832 if (!NT_SUCCESS(Status))
833 {
834 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
835 KEBUGCHECK(0);
836 }
837 MmLockAddressSpace(AddressSpace);
838 Status = MmCreateVirtualMapping(AddressSpace->Process,
839 Address,
840 Region->Protect,
841 &Page,
842 1);
843 if (!NT_SUCCESS(Status))
844 {
845 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
846 KEBUGCHECK(0);
847 return(Status);
848 }
849
850 /*
851 * Store the swap entry for later use.
852 */
853 MmSetSavedSwapEntryPage(Page, SwapEntry);
854
855 /*
856 * Add the page to the process's working set
857 */
858 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
859
860 /*
861 * Finish the operation
862 */
863 if (Locked)
864 {
865 MmLockPage(Page);
866 }
867 PageOp->Status = STATUS_SUCCESS;
868 MmspCompleteAndReleasePageOp(PageOp);
869 DPRINT("Address 0x%.8X\n", Address);
870 return(STATUS_SUCCESS);
871 }
872
873 /*
874 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
875 */
876 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
877 {
878 MmUnlockSectionSegment(Segment);
879 /*
880 * Just map the desired physical page
881 */
882 Page = Offset >> PAGE_SHIFT;
883 Status = MmCreateVirtualMappingUnsafe(AddressSpace->Process,
884 Address,
885 Region->Protect,
886 &Page,
887 1);
888 if (!NT_SUCCESS(Status))
889 {
890 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
891 KEBUGCHECK(0);
892 return(Status);
893 }
894 /*
895 * Don't add an rmap entry since the page mapped could be for
896 * anything.
897 */
898 if (Locked)
899 {
900 MmLockPageUnsafe(Page);
901 }
902
903 /*
904 * Cleanup and release locks
905 */
906 PageOp->Status = STATUS_SUCCESS;
907 MmspCompleteAndReleasePageOp(PageOp);
908 DPRINT("Address 0x%.8X\n", Address);
909 return(STATUS_SUCCESS);
910 }
911
912 /*
913 * Map anonymous memory for BSS sections
914 */
915 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
916 {
917 MmUnlockSectionSegment(Segment);
918 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
919 if (!NT_SUCCESS(Status))
920 {
921 MmUnlockAddressSpace(AddressSpace);
922 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
923 MmLockAddressSpace(AddressSpace);
924 }
925 if (!NT_SUCCESS(Status))
926 {
927 KEBUGCHECK(0);
928 }
929 Status = MmCreateVirtualMapping(AddressSpace->Process,
930 Address,
931 Region->Protect,
932 &Page,
933 1);
934 if (!NT_SUCCESS(Status))
935 {
936 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
937 KEBUGCHECK(0);
938 return(Status);
939 }
940 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
941 if (Locked)
942 {
943 MmLockPage(Page);
944 }
945
946 /*
947 * Cleanup and release locks
948 */
949 PageOp->Status = STATUS_SUCCESS;
950 MmspCompleteAndReleasePageOp(PageOp);
951 DPRINT("Address 0x%.8X\n", Address);
952 return(STATUS_SUCCESS);
953 }
954
955 /*
956 * Get the entry corresponding to the offset within the section
957 */
958 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
959
960 if (Entry == 0)
961 {
962 /*
963 * If the entry is zero (and it can't change because we have
964 * locked the segment) then we need to load the page.
965 */
966
967 /*
968 * Release all our locks and read in the page from disk
969 */
970 MmUnlockSectionSegment(Segment);
971 MmUnlockAddressSpace(AddressSpace);
972
973 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
974 (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
975 {
976 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
977 if (!NT_SUCCESS(Status))
978 {
979 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
980 }
981 }
982 else
983 {
984 Status = MiReadPage(MemoryArea, Offset, &Page);
985 if (!NT_SUCCESS(Status))
986 {
987 DPRINT1("MiReadPage failed (Status %x)\n", Status);
988 }
989 }
990 if (!NT_SUCCESS(Status))
991 {
992 /*
993 * FIXME: What do we know in this case?
994 */
995 /*
996 * Cleanup and release locks
997 */
998 MmLockAddressSpace(AddressSpace);
999 PageOp->Status = Status;
1000 MmspCompleteAndReleasePageOp(PageOp);
1001 DPRINT("Address 0x%.8X\n", Address);
1002 return(Status);
1003 }
1004 /*
1005 * Relock the address space and segment
1006 */
1007 MmLockAddressSpace(AddressSpace);
1008 MmLockSectionSegment(Segment);
1009
1010 /*
1011 * Check the entry. No one should change the status of a page
1012 * that has a pending page-in.
1013 */
1014 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1015 if (Entry != Entry1)
1016 {
1017 DbgPrint("Someone changed ppte entry while we slept\n");
1018 KEBUGCHECK(0);
1019 }
1020
1021 /*
1022 * Mark the offset within the section as having valid, in-memory
1023 * data
1024 */
1025 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1026 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1027 MmUnlockSectionSegment(Segment);
1028
1029 Status = MmCreateVirtualMapping(AddressSpace->Process,
1030 Address,
1031 Attributes,
1032 &Page,
1033 1);
1034 if (!NT_SUCCESS(Status))
1035 {
1036 DbgPrint("Unable to create virtual mapping\n");
1037 KEBUGCHECK(0);
1038 }
1039 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1040
1041 if (Locked)
1042 {
1043 MmLockPage(Page);
1044 }
1045 PageOp->Status = STATUS_SUCCESS;
1046 MmspCompleteAndReleasePageOp(PageOp);
1047 DPRINT("Address 0x%.8X\n", Address);
1048 return(STATUS_SUCCESS);
1049 }
1050 else if (IS_SWAP_FROM_SSE(Entry))
1051 {
1052 SWAPENTRY SwapEntry;
1053
1054 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1055
1056 /*
1057 * Release all our locks and read in the page from disk
1058 */
1059 MmUnlockSectionSegment(Segment);
1060
1061 MmUnlockAddressSpace(AddressSpace);
1062
1063 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1064 if (!NT_SUCCESS(Status))
1065 {
1066 KEBUGCHECK(0);
1067 }
1068
1069 Status = MmReadFromSwapPage(SwapEntry, Page);
1070 if (!NT_SUCCESS(Status))
1071 {
1072 KEBUGCHECK(0);
1073 }
1074
1075 /*
1076 * Relock the address space and segment
1077 */
1078 MmLockAddressSpace(AddressSpace);
1079 MmLockSectionSegment(Segment);
1080
1081 /*
1082 * Check the entry. No one should change the status of a page
1083 * that has a pending page-in.
1084 */
1085 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1086 if (Entry != Entry1)
1087 {
1088 DbgPrint("Someone changed ppte entry while we slept\n");
1089 KEBUGCHECK(0);
1090 }
1091
1092 /*
1093 * Mark the offset within the section as having valid, in-memory
1094 * data
1095 */
1096 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1097 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1098 MmUnlockSectionSegment(Segment);
1099
1100 /*
1101 * Save the swap entry.
1102 */
1103 MmSetSavedSwapEntryPage(Page, SwapEntry);
1104 Status = MmCreateVirtualMapping(AddressSpace->Process,
1105 Address,
1106 Region->Protect,
1107 &Page,
1108 1);
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 = PFN_FROM_SSE(Entry);
1132
1133 MmSharePageEntrySectionSegment(Segment, Offset);
1134 MmUnlockSectionSegment(Segment);
1135
1136 Status = MmCreateVirtualMapping(AddressSpace->Process,
1137 Address,
1138 Attributes,
1139 &Page,
1140 1);
1141 if (!NT_SUCCESS(Status))
1142 {
1143 DbgPrint("Unable to create virtual mapping\n");
1144 KEBUGCHECK(0);
1145 }
1146 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1147 if (Locked)
1148 {
1149 MmLockPage(Page);
1150 }
1151 PageOp->Status = STATUS_SUCCESS;
1152 MmspCompleteAndReleasePageOp(PageOp);
1153 DPRINT("Address 0x%.8X\n", Address);
1154 return(STATUS_SUCCESS);
1155 }
1156 }
1157
1158 NTSTATUS
1159 NTAPI
1160 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1161 MEMORY_AREA* MemoryArea,
1162 PVOID Address,
1163 BOOLEAN Locked)
1164 {
1165 PMM_SECTION_SEGMENT Segment;
1166 PSECTION_OBJECT Section;
1167 PFN_TYPE OldPage;
1168 PFN_TYPE NewPage;
1169 NTSTATUS Status;
1170 PVOID PAddress;
1171 ULONG Offset;
1172 PMM_PAGEOP PageOp;
1173 PMM_REGION Region;
1174 ULONG Entry;
1175
1176 /*
1177 * Check if the page has been paged out or has already been set readwrite
1178 */
1179 if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1180 MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1181 {
1182 DPRINT("Address 0x%.8X\n", Address);
1183 return(STATUS_SUCCESS);
1184 }
1185
1186 /*
1187 * Find the offset of the page
1188 */
1189 PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
1190 Offset = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress
1191 + MemoryArea->Data.SectionData.ViewOffset;
1192
1193 Segment = MemoryArea->Data.SectionData.Segment;
1194 Section = MemoryArea->Data.SectionData.Section;
1195 Region = MmFindRegion(MemoryArea->StartingAddress,
1196 &MemoryArea->Data.SectionData.RegionListHead,
1197 Address, NULL);
1198 /*
1199 * Lock the segment
1200 */
1201 MmLockSectionSegment(Segment);
1202
1203 OldPage = MmGetPfnForProcess(NULL, Address);
1204 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1205
1206 MmUnlockSectionSegment(Segment);
1207
1208 /*
1209 * Check if we are doing COW
1210 */
1211 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1212 (Region->Protect == PAGE_READWRITE ||
1213 Region->Protect == PAGE_EXECUTE_READWRITE)))
1214 {
1215 DPRINT("Address 0x%.8X\n", Address);
1216 return(STATUS_UNSUCCESSFUL);
1217 }
1218
1219 if (IS_SWAP_FROM_SSE(Entry) ||
1220 PFN_FROM_SSE(Entry) != OldPage)
1221 {
1222 /* This is a private page. We must only change the page protection. */
1223 MmSetPageProtect(AddressSpace->Process, PAddress, Region->Protect);
1224 return(STATUS_SUCCESS);
1225 }
1226
1227 /*
1228 * Get or create a pageop
1229 */
1230 PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset,
1231 MM_PAGEOP_ACCESSFAULT, FALSE);
1232 if (PageOp == NULL)
1233 {
1234 DPRINT1("MmGetPageOp failed\n");
1235 KEBUGCHECK(0);
1236 }
1237
1238 /*
1239 * Wait for any other operations to complete
1240 */
1241 if (PageOp->Thread != PsGetCurrentThread())
1242 {
1243 MmUnlockAddressSpace(AddressSpace);
1244 Status = MmspWaitForPageOpCompletionEvent(PageOp);
1245 /*
1246 * Check for various strange conditions
1247 */
1248 if (Status == STATUS_TIMEOUT)
1249 {
1250 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1251 KEBUGCHECK(0);
1252 }
1253 if (PageOp->Status == STATUS_PENDING)
1254 {
1255 DPRINT1("Woke for page op before completion\n");
1256 KEBUGCHECK(0);
1257 }
1258 /*
1259 * Restart the operation
1260 */
1261 MmLockAddressSpace(AddressSpace);
1262 MmspCompleteAndReleasePageOp(PageOp);
1263 DPRINT("Address 0x%.8X\n", Address);
1264 return(STATUS_MM_RESTART_OPERATION);
1265 }
1266
1267 /*
1268 * Release locks now we have the pageop
1269 */
1270 MmUnlockAddressSpace(AddressSpace);
1271
1272 /*
1273 * Allocate a page
1274 */
1275 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1276 if (!NT_SUCCESS(Status))
1277 {
1278 KEBUGCHECK(0);
1279 }
1280
1281 /*
1282 * Copy the old page
1283 */
1284 MiCopyFromUserPage(NewPage, PAddress);
1285
1286 MmLockAddressSpace(AddressSpace);
1287 /*
1288 * Delete the old entry.
1289 */
1290 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1291
1292 /*
1293 * Set the PTE to point to the new page
1294 */
1295 Status = MmCreateVirtualMapping(AddressSpace->Process,
1296 Address,
1297 Region->Protect,
1298 &NewPage,
1299 1);
1300 if (!NT_SUCCESS(Status))
1301 {
1302 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1303 KEBUGCHECK(0);
1304 return(Status);
1305 }
1306 if (!NT_SUCCESS(Status))
1307 {
1308 DbgPrint("Unable to create virtual mapping\n");
1309 KEBUGCHECK(0);
1310 }
1311 if (Locked)
1312 {
1313 MmLockPage(NewPage);
1314 MmUnlockPage(OldPage);
1315 }
1316
1317 /*
1318 * Unshare the old page.
1319 */
1320 MmDeleteRmap(OldPage, AddressSpace->Process, PAddress);
1321 MmInsertRmap(NewPage, AddressSpace->Process, PAddress);
1322 MmLockSectionSegment(Segment);
1323 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
1324 MmUnlockSectionSegment(Segment);
1325
1326 PageOp->Status = STATUS_SUCCESS;
1327 MmspCompleteAndReleasePageOp(PageOp);
1328 DPRINT("Address 0x%.8X\n", Address);
1329 return(STATUS_SUCCESS);
1330 }
1331
1332 VOID
1333 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1334 {
1335 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1336 BOOL WasDirty;
1337 PFN_TYPE Page;
1338
1339 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1340 if (Process)
1341 {
1342 MmLockAddressSpace(&Process->AddressSpace);
1343 }
1344
1345 MmDeleteVirtualMapping(Process,
1346 Address,
1347 FALSE,
1348 &WasDirty,
1349 &Page);
1350 if (WasDirty)
1351 {
1352 PageOutContext->WasDirty = TRUE;
1353 }
1354 if (!PageOutContext->Private)
1355 {
1356 MmLockSectionSegment(PageOutContext->Segment);
1357 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1358 PageOutContext->Segment,
1359 PageOutContext->Offset,
1360 PageOutContext->WasDirty,
1361 TRUE);
1362 MmUnlockSectionSegment(PageOutContext->Segment);
1363 }
1364 if (Process)
1365 {
1366 MmUnlockAddressSpace(&Process->AddressSpace);
1367 }
1368
1369 if (PageOutContext->Private)
1370 {
1371 MmReleasePageMemoryConsumer(MC_USER, Page);
1372 }
1373
1374 DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
1375 }
1376
1377 NTSTATUS
1378 NTAPI
1379 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1380 MEMORY_AREA* MemoryArea,
1381 PVOID Address,
1382 PMM_PAGEOP PageOp)
1383 {
1384 PFN_TYPE Page;
1385 MM_SECTION_PAGEOUT_CONTEXT Context;
1386 SWAPENTRY SwapEntry;
1387 ULONG Entry;
1388 ULONG FileOffset;
1389 NTSTATUS Status;
1390 PFILE_OBJECT FileObject;
1391 PBCB Bcb = NULL;
1392 BOOLEAN DirectMapped;
1393 BOOLEAN IsImageSection;
1394
1395 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1396
1397 /*
1398 * Get the segment and section.
1399 */
1400 Context.Segment = MemoryArea->Data.SectionData.Segment;
1401 Context.Section = MemoryArea->Data.SectionData.Section;
1402
1403 Context.Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
1404 + MemoryArea->Data.SectionData.ViewOffset;
1405 FileOffset = Context.Offset + Context.Segment->FileOffset;
1406
1407 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1408
1409 FileObject = Context.Section->FileObject;
1410 DirectMapped = FALSE;
1411 if (FileObject != NULL &&
1412 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
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 ((FileOffset % PAGE_SIZE) == 0 &&
1422 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1423 {
1424 DirectMapped = TRUE;
1425 }
1426 }
1427
1428
1429 /*
1430 * This should never happen since mappings of physical memory are never
1431 * placed in the rmap lists.
1432 */
1433 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1434 {
1435 DPRINT1("Trying to page out from physical memory section address 0x%X "
1436 "process %d\n", Address,
1437 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1438 KEBUGCHECK(0);
1439 }
1440
1441 /*
1442 * Get the section segment entry and the physical address.
1443 */
1444 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1445 if (!MmIsPagePresent(AddressSpace->Process, Address))
1446 {
1447 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1448 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1449 KEBUGCHECK(0);
1450 }
1451 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1452 SwapEntry = MmGetSavedSwapEntryPage(Page);
1453
1454 /*
1455 * Prepare the context structure for the rmap delete call.
1456 */
1457 Context.WasDirty = FALSE;
1458 if (Context.Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
1459 IS_SWAP_FROM_SSE(Entry) ||
1460 PFN_FROM_SSE(Entry) != Page)
1461 {
1462 Context.Private = TRUE;
1463 }
1464 else
1465 {
1466 Context.Private = FALSE;
1467 }
1468
1469 /*
1470 * Take an additional reference to the page or the cache segment.
1471 */
1472 if (DirectMapped && !Context.Private)
1473 {
1474 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1475 {
1476 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1477 KEBUGCHECK(0);
1478 }
1479 }
1480 else
1481 {
1482 MmReferencePage(Page);
1483 }
1484
1485 MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
1486
1487 /*
1488 * If this wasn't a private page then we should have reduced the entry to
1489 * zero by deleting all the rmaps.
1490 */
1491 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1492 {
1493 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
1494 !(Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
1495 {
1496 KEBUGCHECK(0);
1497 }
1498 }
1499
1500 /*
1501 * If the page wasn't dirty then we can just free it as for a readonly page.
1502 * Since we unmapped all the mappings above we know it will not suddenly
1503 * become dirty.
1504 * If the page is from a pagefile section and has no swap entry,
1505 * we can't free the page at this point.
1506 */
1507 SwapEntry = MmGetSavedSwapEntryPage(Page);
1508 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT)
1509 {
1510 if (Context.Private)
1511 {
1512 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1513 Context.WasDirty ? "dirty" : "clean", Address);
1514 KEBUGCHECK(0);
1515 }
1516 if (!Context.WasDirty && SwapEntry != 0)
1517 {
1518 MmSetSavedSwapEntryPage(Page, 0);
1519 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1520 MmReleasePageMemoryConsumer(MC_USER, Page);
1521 PageOp->Status = STATUS_SUCCESS;
1522 MmspCompleteAndReleasePageOp(PageOp);
1523 return(STATUS_SUCCESS);
1524 }
1525 }
1526 else if (Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
1527 {
1528 if (Context.Private)
1529 {
1530 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1531 Context.WasDirty ? "dirty" : "clean", Address);
1532 KEBUGCHECK(0);
1533 }
1534 if (!Context.WasDirty || SwapEntry != 0)
1535 {
1536 MmSetSavedSwapEntryPage(Page, 0);
1537 if (SwapEntry != 0)
1538 {
1539 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1540 }
1541 MmReleasePageMemoryConsumer(MC_USER, Page);
1542 PageOp->Status = STATUS_SUCCESS;
1543 MmspCompleteAndReleasePageOp(PageOp);
1544 return(STATUS_SUCCESS);
1545 }
1546 }
1547 else if (!Context.Private && DirectMapped)
1548 {
1549 if (SwapEntry != 0)
1550 {
1551 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1552 Address);
1553 KEBUGCHECK(0);
1554 }
1555 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1556 if (!NT_SUCCESS(Status))
1557 {
1558 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1559 KEBUGCHECK(0);
1560 }
1561 PageOp->Status = STATUS_SUCCESS;
1562 MmspCompleteAndReleasePageOp(PageOp);
1563 return(STATUS_SUCCESS);
1564 }
1565 else if (!Context.WasDirty && !DirectMapped && !Context.Private)
1566 {
1567 if (SwapEntry != 0)
1568 {
1569 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1570 Address);
1571 KEBUGCHECK(0);
1572 }
1573 MmReleasePageMemoryConsumer(MC_USER, Page);
1574 PageOp->Status = STATUS_SUCCESS;
1575 MmspCompleteAndReleasePageOp(PageOp);
1576 return(STATUS_SUCCESS);
1577 }
1578 else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
1579 {
1580 MmSetSavedSwapEntryPage(Page, 0);
1581 MmLockAddressSpace(AddressSpace);
1582 Status = MmCreatePageFileMapping(AddressSpace->Process,
1583 Address,
1584 SwapEntry);
1585 MmUnlockAddressSpace(AddressSpace);
1586 if (!NT_SUCCESS(Status))
1587 {
1588 KEBUGCHECK(0);
1589 }
1590 MmReleasePageMemoryConsumer(MC_USER, Page);
1591 PageOp->Status = STATUS_SUCCESS;
1592 MmspCompleteAndReleasePageOp(PageOp);
1593 return(STATUS_SUCCESS);
1594 }
1595
1596 /*
1597 * If necessary, allocate an entry in the paging file for this page
1598 */
1599 if (SwapEntry == 0)
1600 {
1601 SwapEntry = MmAllocSwapPage();
1602 if (SwapEntry == 0)
1603 {
1604 MmShowOutOfSpaceMessagePagingFile();
1605 MmLockAddressSpace(AddressSpace);
1606 /*
1607 * For private pages restore the old mappings.
1608 */
1609 if (Context.Private)
1610 {
1611 Status = MmCreateVirtualMapping(AddressSpace->Process,
1612 Address,
1613 MemoryArea->Protect,
1614 &Page,
1615 1);
1616 MmSetDirtyPage(AddressSpace->Process, Address);
1617 MmInsertRmap(Page,
1618 AddressSpace->Process,
1619 Address);
1620 }
1621 else
1622 {
1623 /*
1624 * For non-private pages if the page wasn't direct mapped then
1625 * set it back into the section segment entry so we don't loose
1626 * our copy. Otherwise it will be handled by the cache manager.
1627 */
1628 Status = MmCreateVirtualMapping(AddressSpace->Process,
1629 Address,
1630 MemoryArea->Protect,
1631 &Page,
1632 1);
1633 MmSetDirtyPage(AddressSpace->Process, Address);
1634 MmInsertRmap(Page,
1635 AddressSpace->Process,
1636 Address);
1637 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1638 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1639 }
1640 MmUnlockAddressSpace(AddressSpace);
1641 PageOp->Status = STATUS_UNSUCCESSFUL;
1642 MmspCompleteAndReleasePageOp(PageOp);
1643 return(STATUS_PAGEFILE_QUOTA);
1644 }
1645 }
1646
1647 /*
1648 * Write the page to the pagefile
1649 */
1650 Status = MmWriteToSwapPage(SwapEntry, Page);
1651 if (!NT_SUCCESS(Status))
1652 {
1653 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1654 Status);
1655 /*
1656 * As above: undo our actions.
1657 * FIXME: Also free the swap page.
1658 */
1659 MmLockAddressSpace(AddressSpace);
1660 if (Context.Private)
1661 {
1662 Status = MmCreateVirtualMapping(AddressSpace->Process,
1663 Address,
1664 MemoryArea->Protect,
1665 &Page,
1666 1);
1667 MmSetDirtyPage(AddressSpace->Process, Address);
1668 MmInsertRmap(Page,
1669 AddressSpace->Process,
1670 Address);
1671 }
1672 else
1673 {
1674 Status = MmCreateVirtualMapping(AddressSpace->Process,
1675 Address,
1676 MemoryArea->Protect,
1677 &Page,
1678 1);
1679 MmSetDirtyPage(AddressSpace->Process, Address);
1680 MmInsertRmap(Page,
1681 AddressSpace->Process,
1682 Address);
1683 Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
1684 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1685 }
1686 MmUnlockAddressSpace(AddressSpace);
1687 PageOp->Status = STATUS_UNSUCCESSFUL;
1688 MmspCompleteAndReleasePageOp(PageOp);
1689 return(STATUS_UNSUCCESSFUL);
1690 }
1691
1692 /*
1693 * Otherwise we have succeeded.
1694 */
1695 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1696 MmSetSavedSwapEntryPage(Page, 0);
1697 if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
1698 Context.Segment->Characteristics & IMAGE_SCN_MEM_SHARED)
1699 {
1700 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
1701 }
1702 else
1703 {
1704 MmReleasePageMemoryConsumer(MC_USER, Page);
1705 }
1706
1707 if (Context.Private)
1708 {
1709 MmLockAddressSpace(AddressSpace);
1710 Status = MmCreatePageFileMapping(AddressSpace->Process,
1711 Address,
1712 SwapEntry);
1713 MmUnlockAddressSpace(AddressSpace);
1714 if (!NT_SUCCESS(Status))
1715 {
1716 KEBUGCHECK(0);
1717 }
1718 }
1719 else
1720 {
1721 Entry = MAKE_SWAP_SSE(SwapEntry);
1722 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1723 }
1724
1725 PageOp->Status = STATUS_SUCCESS;
1726 MmspCompleteAndReleasePageOp(PageOp);
1727 return(STATUS_SUCCESS);
1728 }
1729
1730 NTSTATUS
1731 NTAPI
1732 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1733 PMEMORY_AREA MemoryArea,
1734 PVOID Address,
1735 PMM_PAGEOP PageOp)
1736 {
1737 ULONG Offset;
1738 PSECTION_OBJECT Section;
1739 PMM_SECTION_SEGMENT Segment;
1740 PFN_TYPE Page;
1741 SWAPENTRY SwapEntry;
1742 ULONG Entry;
1743 BOOLEAN Private;
1744 NTSTATUS Status;
1745 PFILE_OBJECT FileObject;
1746 PBCB Bcb = NULL;
1747 BOOLEAN DirectMapped;
1748 BOOLEAN IsImageSection;
1749
1750 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1751
1752 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
1753 + MemoryArea->Data.SectionData.ViewOffset;
1754
1755 /*
1756 * Get the segment and section.
1757 */
1758 Segment = MemoryArea->Data.SectionData.Segment;
1759 Section = MemoryArea->Data.SectionData.Section;
1760 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1761
1762 FileObject = Section->FileObject;
1763 DirectMapped = FALSE;
1764 if (FileObject != NULL &&
1765 !(Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
1766 {
1767 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1768
1769 /*
1770 * If the file system is letting us go directly to the cache and the
1771 * memory area was mapped at an offset in the file which is page aligned
1772 * then note this is a direct mapped page.
1773 */
1774 if (((Offset + Segment->FileOffset) % PAGE_SIZE) == 0 &&
1775 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1776 {
1777 DirectMapped = TRUE;
1778 }
1779 }
1780
1781 /*
1782 * This should never happen since mappings of physical memory are never
1783 * placed in the rmap lists.
1784 */
1785 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1786 {
1787 DPRINT1("Trying to write back page from physical memory mapped at %X "
1788 "process %d\n", Address,
1789 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1790 KEBUGCHECK(0);
1791 }
1792
1793 /*
1794 * Get the section segment entry and the physical address.
1795 */
1796 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1797 if (!MmIsPagePresent(AddressSpace->Process, Address))
1798 {
1799 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1800 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1801 KEBUGCHECK(0);
1802 }
1803 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1804 SwapEntry = MmGetSavedSwapEntryPage(Page);
1805
1806 /*
1807 * Check for a private (COWed) page.
1808 */
1809 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
1810 IS_SWAP_FROM_SSE(Entry) ||
1811 PFN_FROM_SSE(Entry) != Page)
1812 {
1813 Private = TRUE;
1814 }
1815 else
1816 {
1817 Private = FALSE;
1818 }
1819
1820 /*
1821 * Speculatively set all mappings of the page to clean.
1822 */
1823 MmSetCleanAllRmaps(Page);
1824
1825 /*
1826 * If this page was direct mapped from the cache then the cache manager
1827 * will take care of writing it back to disk.
1828 */
1829 if (DirectMapped && !Private)
1830 {
1831 ASSERT(SwapEntry == 0);
1832 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
1833 PageOp->Status = STATUS_SUCCESS;
1834 MmspCompleteAndReleasePageOp(PageOp);
1835 return(STATUS_SUCCESS);
1836 }
1837
1838 /*
1839 * If necessary, allocate an entry in the paging file for this page
1840 */
1841 if (SwapEntry == 0)
1842 {
1843 SwapEntry = MmAllocSwapPage();
1844 if (SwapEntry == 0)
1845 {
1846 MmSetDirtyAllRmaps(Page);
1847 PageOp->Status = STATUS_UNSUCCESSFUL;
1848 MmspCompleteAndReleasePageOp(PageOp);
1849 return(STATUS_PAGEFILE_QUOTA);
1850 }
1851 MmSetSavedSwapEntryPage(Page, SwapEntry);
1852 }
1853
1854 /*
1855 * Write the page to the pagefile
1856 */
1857 Status = MmWriteToSwapPage(SwapEntry, Page);
1858 if (!NT_SUCCESS(Status))
1859 {
1860 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1861 Status);
1862 MmSetDirtyAllRmaps(Page);
1863 PageOp->Status = STATUS_UNSUCCESSFUL;
1864 MmspCompleteAndReleasePageOp(PageOp);
1865 return(STATUS_UNSUCCESSFUL);
1866 }
1867
1868 /*
1869 * Otherwise we have succeeded.
1870 */
1871 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
1872 PageOp->Status = STATUS_SUCCESS;
1873 MmspCompleteAndReleasePageOp(PageOp);
1874 return(STATUS_SUCCESS);
1875 }
1876
1877 VOID STATIC
1878 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1879 PVOID BaseAddress,
1880 ULONG RegionSize,
1881 ULONG OldType,
1882 ULONG OldProtect,
1883 ULONG NewType,
1884 ULONG NewProtect)
1885 {
1886 PMEMORY_AREA MemoryArea;
1887 PMM_SECTION_SEGMENT Segment;
1888 BOOL DoCOW = FALSE;
1889 ULONG i;
1890
1891 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
1892 Segment = MemoryArea->Data.SectionData.Segment;
1893
1894 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1895 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1896 {
1897 DoCOW = TRUE;
1898 }
1899
1900 if (OldProtect != NewProtect)
1901 {
1902 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1903 {
1904 PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
1905 ULONG Protect = NewProtect;
1906
1907 /*
1908 * If we doing COW for this segment then check if the page is
1909 * already private.
1910 */
1911 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1912 {
1913 ULONG Offset;
1914 ULONG Entry;
1915 PFN_TYPE Page;
1916
1917 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
1918 + MemoryArea->Data.SectionData.ViewOffset;
1919 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1920 Page = MmGetPfnForProcess(AddressSpace->Process, Address);
1921
1922 Protect = PAGE_READONLY;
1923 if (Segment->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
1924 IS_SWAP_FROM_SSE(Entry) ||
1925 PFN_FROM_SSE(Entry) != Page)
1926 {
1927 Protect = NewProtect;
1928 }
1929 }
1930
1931 if (MmIsPagePresent(AddressSpace->Process, Address))
1932 {
1933 MmSetPageProtect(AddressSpace->Process, Address,
1934 Protect);
1935 }
1936 }
1937 }
1938 }
1939
1940 NTSTATUS
1941 NTAPI
1942 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1943 PMEMORY_AREA MemoryArea,
1944 PVOID BaseAddress,
1945 ULONG Length,
1946 ULONG Protect,
1947 PULONG OldProtect)
1948 {
1949 PMM_REGION Region;
1950 NTSTATUS Status;
1951 ULONG_PTR MaxLength;
1952
1953 MaxLength = (ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)BaseAddress;
1954 if (Length > MaxLength)
1955 Length = MaxLength;
1956
1957 Region = MmFindRegion(MemoryArea->StartingAddress,
1958 &MemoryArea->Data.SectionData.RegionListHead,
1959 BaseAddress, NULL);
1960 if ((MemoryArea->Flags & SEC_NO_CHANGE) &&
1961 Region->Protect != Protect)
1962 {
1963 CHECKPOINT1;
1964 return STATUS_INVALID_PAGE_PROTECTION;
1965 }
1966
1967 *OldProtect = Region->Protect;
1968 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
1969 &MemoryArea->Data.SectionData.RegionListHead,
1970 BaseAddress, Length, Region->Type, Protect,
1971 MmAlterViewAttributes);
1972
1973 return(Status);
1974 }
1975
1976 NTSTATUS STDCALL
1977 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1978 PVOID Address,
1979 PMEMORY_BASIC_INFORMATION Info,
1980 PULONG ResultLength)
1981 {
1982 PMM_REGION Region;
1983 PVOID RegionBaseAddress;
1984 PSECTION_OBJECT Section;
1985 PMM_SECTION_SEGMENT Segment;
1986
1987 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
1988 &MemoryArea->Data.SectionData.RegionListHead,
1989 Address, &RegionBaseAddress);
1990 if (Region == NULL)
1991 {
1992 return STATUS_UNSUCCESSFUL;
1993 }
1994
1995 Section = MemoryArea->Data.SectionData.Section;
1996 if (Section->AllocationAttributes & SEC_IMAGE)
1997 {
1998 Segment = MemoryArea->Data.SectionData.Segment;
1999 Info->AllocationBase = (PBYTE)MemoryArea->StartingAddress - Segment->VirtualAddress;
2000 Info->Type = MEM_IMAGE;
2001 }
2002 else
2003 {
2004 Info->AllocationBase = MemoryArea->StartingAddress;
2005 Info->Type = MEM_MAPPED;
2006 }
2007 Info->BaseAddress = RegionBaseAddress;
2008 Info->AllocationProtect = MemoryArea->Protect;
2009 Info->RegionSize = Region->Length;
2010 Info->State = MEM_COMMIT;
2011 Info->Protect = Region->Protect;
2012
2013 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2014 return(STATUS_SUCCESS);
2015 }
2016
2017 VOID
2018 NTAPI
2019 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2020 {
2021 ULONG Length;
2022 ULONG Offset;
2023 ULONG Entry;
2024 ULONG SavedSwapEntry;
2025 PFN_TYPE Page;
2026
2027 Page = 0;
2028
2029 Length = PAGE_ROUND_UP(Segment->Length);
2030 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2031 {
2032 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2033 if (Entry)
2034 {
2035 if (IS_SWAP_FROM_SSE(Entry))
2036 {
2037 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2038 }
2039 else
2040 {
2041 Page = PFN_FROM_SSE(Entry);
2042 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2043 if (SavedSwapEntry != 0)
2044 {
2045 MmSetSavedSwapEntryPage(Page, 0);
2046 MmFreeSwapPage(SavedSwapEntry);
2047 }
2048 MmReleasePageMemoryConsumer(MC_USER, Page);
2049 }
2050 MmSetPageEntrySectionSegment(Segment, Offset, 0);
2051 }
2052 }
2053 }
2054
2055 VOID STDCALL
2056 MmpDeleteSection(PVOID ObjectBody)
2057 {
2058 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
2059
2060 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2061 if (Section->AllocationAttributes & SEC_IMAGE)
2062 {
2063 ULONG i;
2064 ULONG NrSegments;
2065 ULONG RefCount;
2066 PMM_SECTION_SEGMENT SectionSegments;
2067
2068 /*
2069 * NOTE: Section->ImageSection can be NULL for short time
2070 * during the section creating. If we fail for some reason
2071 * until the image section is properly initialized we shouldn't
2072 * process further here.
2073 */
2074 if (Section->ImageSection == NULL)
2075 return;
2076
2077 SectionSegments = Section->ImageSection->Segments;
2078 NrSegments = Section->ImageSection->NrSegments;
2079
2080 for (i = 0; i < NrSegments; i++)
2081 {
2082 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2083 {
2084 MmLockSectionSegment(&SectionSegments[i]);
2085 }
2086 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2087 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2088 {
2089 if (RefCount == 0)
2090 {
2091 MmpFreePageFileSegment(&SectionSegments[i]);
2092 }
2093 MmUnlockSectionSegment(&SectionSegments[i]);
2094 }
2095 }
2096 }
2097 else
2098 {
2099 /*
2100 * NOTE: Section->Segment can be NULL for short time
2101 * during the section creating.
2102 */
2103 if (Section->Segment == NULL)
2104 return;
2105
2106 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2107 {
2108 MmpFreePageFileSegment(Section->Segment);
2109 MmFreePageTablesSectionSegment(Section->Segment);
2110 ExFreePool(Section->Segment);
2111 Section->Segment = NULL;
2112 }
2113 else
2114 {
2115 InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2116 }
2117 }
2118 if (Section->FileObject != NULL)
2119 {
2120 CcRosDereferenceCache(Section->FileObject);
2121 ObDereferenceObject(Section->FileObject);
2122 Section->FileObject = NULL;
2123 }
2124 }
2125
2126 VOID STDCALL
2127 MmpCloseSection(PVOID ObjectBody,
2128 ULONG HandleCount)
2129 {
2130 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2131 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
2132 }
2133
2134 NTSTATUS
2135 INIT_FUNCTION
2136 NTAPI
2137 MmCreatePhysicalMemorySection(VOID)
2138 {
2139 PSECTION_OBJECT PhysSection;
2140 NTSTATUS Status;
2141 OBJECT_ATTRIBUTES Obj;
2142 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2143 LARGE_INTEGER SectionSize;
2144
2145 /*
2146 * Create the section mapping physical memory
2147 */
2148 SectionSize.QuadPart = 0xFFFFFFFF;
2149 InitializeObjectAttributes(&Obj,
2150 &Name,
2151 OBJ_PERMANENT,
2152 NULL,
2153 NULL);
2154 Status = MmCreateSection(&PhysSection,
2155 SECTION_ALL_ACCESS,
2156 &Obj,
2157 &SectionSize,
2158 PAGE_EXECUTE_READWRITE,
2159 0,
2160 NULL,
2161 NULL);
2162 if (!NT_SUCCESS(Status))
2163 {
2164 DbgPrint("Failed to create PhysicalMemory section\n");
2165 KEBUGCHECK(0);
2166 }
2167 Status = ObInsertObject(PhysSection,
2168 NULL,
2169 SECTION_ALL_ACCESS,
2170 0,
2171 NULL,
2172 NULL);
2173 if (!NT_SUCCESS(Status))
2174 {
2175 ObDereferenceObject(PhysSection);
2176 }
2177 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2178 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2179
2180 return(STATUS_SUCCESS);
2181 }
2182
2183 NTSTATUS
2184 INIT_FUNCTION
2185 NTAPI
2186 MmInitSectionImplementation(VOID)
2187 {
2188 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2189 UNICODE_STRING Name;
2190
2191 DPRINT("Creating Section Object Type\n");
2192
2193 /* Initialize the Section object type */
2194 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2195 RtlInitUnicodeString(&Name, L"Section");
2196 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2197 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION_OBJECT);
2198 ObjectTypeInitializer.PoolType = PagedPool;
2199 ObjectTypeInitializer.UseDefaultObject = TRUE;
2200 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2201 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2202 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2203 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &MmSectionObjectType);
2204
2205 return(STATUS_SUCCESS);
2206 }
2207
2208 NTSTATUS
2209 NTAPI
2210 MmCreatePageFileSection(PSECTION_OBJECT *SectionObject,
2211 ACCESS_MASK DesiredAccess,
2212 POBJECT_ATTRIBUTES ObjectAttributes,
2213 PLARGE_INTEGER UMaximumSize,
2214 ULONG SectionPageProtection,
2215 ULONG AllocationAttributes)
2216 /*
2217 * Create a section which is backed by the pagefile
2218 */
2219 {
2220 LARGE_INTEGER MaximumSize;
2221 PSECTION_OBJECT Section;
2222 PMM_SECTION_SEGMENT Segment;
2223 NTSTATUS Status;
2224
2225 if (UMaximumSize == NULL)
2226 {
2227 return(STATUS_UNSUCCESSFUL);
2228 }
2229 MaximumSize = *UMaximumSize;
2230
2231 /*
2232 * Create the section
2233 */
2234 Status = ObCreateObject(ExGetPreviousMode(),
2235 MmSectionObjectType,
2236 ObjectAttributes,
2237 ExGetPreviousMode(),
2238 NULL,
2239 sizeof(SECTION_OBJECT),
2240 0,
2241 0,
2242 (PVOID*)(PVOID)&Section);
2243 if (!NT_SUCCESS(Status))
2244 {
2245 return(Status);
2246 }
2247
2248 /*
2249 * Initialize it
2250 */
2251 Section->SectionPageProtection = SectionPageProtection;
2252 Section->AllocationAttributes = AllocationAttributes;
2253 Section->Segment = NULL;
2254 Section->FileObject = NULL;
2255 Section->MaximumSize = MaximumSize;
2256 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2257 TAG_MM_SECTION_SEGMENT);
2258 if (Segment == NULL)
2259 {
2260 ObDereferenceObject(Section);
2261 return(STATUS_NO_MEMORY);
2262 }
2263 Section->Segment = Segment;
2264 Segment->ReferenceCount = 1;
2265 ExInitializeFastMutex(&Segment->Lock);
2266 Segment->FileOffset = 0;
2267 Segment->Protection = SectionPageProtection;
2268 Segment->RawLength = MaximumSize.u.LowPart;
2269 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2270 Segment->Flags = MM_PAGEFILE_SEGMENT;
2271 Segment->WriteCopy = FALSE;
2272 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2273 Segment->VirtualAddress = 0;
2274 Segment->Characteristics = 0;
2275 *SectionObject = Section;
2276 return(STATUS_SUCCESS);
2277 }
2278
2279
2280 NTSTATUS
2281 NTAPI
2282 MmCreateDataFileSection(PSECTION_OBJECT *SectionObject,
2283 ACCESS_MASK DesiredAccess,
2284 POBJECT_ATTRIBUTES ObjectAttributes,
2285 PLARGE_INTEGER UMaximumSize,
2286 ULONG SectionPageProtection,
2287 ULONG AllocationAttributes,
2288 HANDLE FileHandle)
2289 /*
2290 * Create a section backed by a data file
2291 */
2292 {
2293 PSECTION_OBJECT Section;
2294 NTSTATUS Status;
2295 LARGE_INTEGER MaximumSize;
2296 PFILE_OBJECT FileObject;
2297 PMM_SECTION_SEGMENT Segment;
2298 ULONG FileAccess;
2299 IO_STATUS_BLOCK Iosb;
2300 LARGE_INTEGER Offset;
2301 CHAR Buffer;
2302 FILE_STANDARD_INFORMATION FileInfo;
2303
2304 /*
2305 * Create the section
2306 */
2307 Status = ObCreateObject(ExGetPreviousMode(),
2308 MmSectionObjectType,
2309 ObjectAttributes,
2310 ExGetPreviousMode(),
2311 NULL,
2312 sizeof(SECTION_OBJECT),
2313 0,
2314 0,
2315 (PVOID*)(PVOID)&Section);
2316 if (!NT_SUCCESS(Status))
2317 {
2318 return(Status);
2319 }
2320 /*
2321 * Initialize it
2322 */
2323 Section->SectionPageProtection = SectionPageProtection;
2324 Section->AllocationAttributes = AllocationAttributes;
2325 Section->Segment = NULL;
2326
2327 /*
2328 * Check file access required
2329 */
2330 if (SectionPageProtection & PAGE_READWRITE ||
2331 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2332 {
2333 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2334 }
2335 else
2336 {
2337 FileAccess = FILE_READ_DATA;
2338 }
2339
2340 /*
2341 * Reference the file handle
2342 */
2343 Status = ObReferenceObjectByHandle(FileHandle,
2344 FileAccess,
2345 IoFileObjectType,
2346 UserMode,
2347 (PVOID*)(PVOID)&FileObject,
2348 NULL);
2349 if (!NT_SUCCESS(Status))
2350 {
2351 ObDereferenceObject(Section);
2352 return(Status);
2353 }
2354
2355 /*
2356 * FIXME: This is propably not entirely correct. We can't look into
2357 * the standard FCB header because it might not be initialized yet
2358 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2359 * standard file information is filled on first request).
2360 */
2361 Status = IoQueryFileInformation(FileObject,
2362 FileStandardInformation,
2363 sizeof(FILE_STANDARD_INFORMATION),
2364 &FileInfo,
2365 &Iosb.Information);
2366 if (!NT_SUCCESS(Status))
2367 {
2368 ObDereferenceObject(Section);
2369 ObDereferenceObject(FileObject);
2370 return Status;
2371 }
2372
2373 /*
2374 * FIXME: Revise this once a locking order for file size changes is
2375 * decided
2376 */
2377 if (UMaximumSize != NULL)
2378 {
2379 MaximumSize = *UMaximumSize;
2380 }
2381 else
2382 {
2383 MaximumSize = FileInfo.EndOfFile;
2384 /* Mapping zero-sized files isn't allowed. */
2385 if (MaximumSize.QuadPart == 0)
2386 {
2387 ObDereferenceObject(Section);
2388 ObDereferenceObject(FileObject);
2389 return STATUS_FILE_INVALID;
2390 }
2391 }
2392
2393 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2394 {
2395 Status = IoSetInformation(FileObject,
2396 FileAllocationInformation,
2397 sizeof(LARGE_INTEGER),
2398 &MaximumSize);
2399 if (!NT_SUCCESS(Status))
2400 {
2401 ObDereferenceObject(Section);
2402 ObDereferenceObject(FileObject);
2403 return(STATUS_SECTION_NOT_EXTENDED);
2404 }
2405 }
2406
2407 if (FileObject->SectionObjectPointer == NULL ||
2408 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2409 {
2410 /*
2411 * Read a bit so caching is initiated for the file object.
2412 * This is only needed because MiReadPage currently cannot
2413 * handle non-cached streams.
2414 */
2415 Offset.QuadPart = 0;
2416 Status = ZwReadFile(FileHandle,
2417 NULL,
2418 NULL,
2419 NULL,
2420 &Iosb,
2421 &Buffer,
2422 sizeof (Buffer),
2423 &Offset,
2424 0);
2425 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2426 {
2427 ObDereferenceObject(Section);
2428 ObDereferenceObject(FileObject);
2429 return(Status);
2430 }
2431 if (FileObject->SectionObjectPointer == NULL ||
2432 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2433 {
2434 /* FIXME: handle this situation */
2435 ObDereferenceObject(Section);
2436 ObDereferenceObject(FileObject);
2437 return STATUS_INVALID_PARAMETER;
2438 }
2439 }
2440
2441 /*
2442 * Lock the file
2443 */
2444 Status = MmspWaitForFileLock(FileObject);
2445 if (Status != STATUS_SUCCESS)
2446 {
2447 ObDereferenceObject(Section);
2448 ObDereferenceObject(FileObject);
2449 return(Status);
2450 }
2451
2452 /*
2453 * If this file hasn't been mapped as a data file before then allocate a
2454 * section segment to describe the data file mapping
2455 */
2456 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2457 {
2458 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2459 TAG_MM_SECTION_SEGMENT);
2460 if (Segment == NULL)
2461 {
2462 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2463 ObDereferenceObject(Section);
2464 ObDereferenceObject(FileObject);
2465 return(STATUS_NO_MEMORY);
2466 }
2467 Section->Segment = Segment;
2468 Segment->ReferenceCount = 1;
2469 ExInitializeFastMutex(&Segment->Lock);
2470 /*
2471 * Set the lock before assigning the segment to the file object
2472 */
2473 ExAcquireFastMutex(&Segment->Lock);
2474 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2475
2476 Segment->FileOffset = 0;
2477 Segment->Protection = SectionPageProtection;
2478 Segment->Flags = MM_DATAFILE_SEGMENT;
2479 Segment->Characteristics = 0;
2480 Segment->WriteCopy = FALSE;
2481 if (AllocationAttributes & SEC_RESERVE)
2482 {
2483 Segment->Length = Segment->RawLength = 0;
2484 }
2485 else
2486 {
2487 Segment->RawLength = MaximumSize.u.LowPart;
2488 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2489 }
2490 Segment->VirtualAddress = 0;
2491 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2492 }
2493 else
2494 {
2495 /*
2496 * If the file is already mapped as a data file then we may need
2497 * to extend it
2498 */
2499 Segment =
2500 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2501 DataSectionObject;
2502 Section->Segment = Segment;
2503 InterlockedIncrementUL(&Segment->ReferenceCount);
2504 MmLockSectionSegment(Segment);
2505
2506 if (MaximumSize.u.LowPart > Segment->RawLength &&
2507 !(AllocationAttributes & SEC_RESERVE))
2508 {
2509 Segment->RawLength = MaximumSize.u.LowPart;
2510 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2511 }
2512 }
2513 MmUnlockSectionSegment(Segment);
2514 Section->FileObject = FileObject;
2515 Section->MaximumSize = MaximumSize;
2516 CcRosReferenceCache(FileObject);
2517 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2518 *SectionObject = Section;
2519 return(STATUS_SUCCESS);
2520 }
2521
2522 /*
2523 TODO: not that great (declaring loaders statically, having to declare all of
2524 them, having to keep them extern, etc.), will fix in the future
2525 */
2526 extern NTSTATUS NTAPI PeFmtCreateSection
2527 (
2528 IN CONST VOID * FileHeader,
2529 IN SIZE_T FileHeaderSize,
2530 IN PVOID File,
2531 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2532 OUT PULONG Flags,
2533 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2534 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2535 );
2536
2537 extern NTSTATUS NTAPI ElfFmtCreateSection
2538 (
2539 IN CONST VOID * FileHeader,
2540 IN SIZE_T FileHeaderSize,
2541 IN PVOID File,
2542 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2543 OUT PULONG Flags,
2544 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2545 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2546 );
2547
2548 /* TODO: this is a standard DDK/PSDK macro */
2549 #ifndef RTL_NUMBER_OF
2550 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2551 #endif
2552
2553 static PEXEFMT_LOADER ExeFmtpLoaders[] =
2554 {
2555 PeFmtCreateSection,
2556 ElfFmtCreateSection
2557 };
2558
2559 static
2560 PMM_SECTION_SEGMENT
2561 NTAPI
2562 ExeFmtpAllocateSegments(IN ULONG NrSegments)
2563 {
2564 SIZE_T SizeOfSegments;
2565 PMM_SECTION_SEGMENT Segments;
2566
2567 /* TODO: check for integer overflow */
2568 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
2569
2570 Segments = ExAllocatePoolWithTag(NonPagedPool,
2571 SizeOfSegments,
2572 TAG_MM_SECTION_SEGMENT);
2573
2574 if(Segments)
2575 RtlZeroMemory(Segments, SizeOfSegments);
2576
2577 return Segments;
2578 }
2579
2580 static
2581 NTSTATUS
2582 NTAPI
2583 ExeFmtpReadFile(IN PVOID File,
2584 IN PLARGE_INTEGER Offset,
2585 IN ULONG Length,
2586 OUT PVOID * Data,
2587 OUT PVOID * AllocBase,
2588 OUT PULONG ReadSize)
2589 {
2590 NTSTATUS Status;
2591 LARGE_INTEGER FileOffset;
2592 ULONG AdjustOffset;
2593 ULONG OffsetAdjustment;
2594 ULONG BufferSize;
2595 ULONG UsedSize;
2596 PVOID Buffer;
2597
2598 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
2599
2600 if(Length == 0)
2601 {
2602 KEBUGCHECK(STATUS_INVALID_PARAMETER_4);
2603 }
2604
2605 FileOffset = *Offset;
2606
2607 /* Negative/special offset: it cannot be used in this context */
2608 if(FileOffset.u.HighPart < 0)
2609 {
2610 KEBUGCHECK(STATUS_INVALID_PARAMETER_5);
2611 }
2612
2613 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
2614 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
2615 FileOffset.u.LowPart = AdjustOffset;
2616
2617 BufferSize = Length + OffsetAdjustment;
2618 BufferSize = PAGE_ROUND_UP(BufferSize);
2619
2620 /*
2621 * It's ok to use paged pool, because this is a temporary buffer only used in
2622 * the loading of executables. The assumption is that MmCreateSection is
2623 * always called at low IRQLs and that these buffers don't survive a brief
2624 * initialization phase
2625 */
2626 Buffer = ExAllocatePoolWithTag(PagedPool,
2627 BufferSize,
2628 TAG('M', 'm', 'X', 'r'));
2629
2630 UsedSize = 0;
2631
2632 #if 0
2633 Status = MmspPageRead(File,
2634 Buffer,
2635 BufferSize,
2636 &FileOffset,
2637 &UsedSize);
2638 #else
2639 /*
2640 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2641 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2642 * to initialize internal state is even worse. Our cache manager is in need of
2643 * professional help
2644 */
2645 {
2646 IO_STATUS_BLOCK Iosb;
2647
2648 Status = ZwReadFile(File,
2649 NULL,
2650 NULL,
2651 NULL,
2652 &Iosb,
2653 Buffer,
2654 BufferSize,
2655 &FileOffset,
2656 NULL);
2657
2658 if(NT_SUCCESS(Status))
2659 {
2660 UsedSize = Iosb.Information;
2661 }
2662 }
2663 #endif
2664
2665 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
2666 {
2667 Status = STATUS_IN_PAGE_ERROR;
2668 ASSERT(!NT_SUCCESS(Status));
2669 }
2670
2671 if(NT_SUCCESS(Status))
2672 {
2673 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
2674 *AllocBase = Buffer;
2675 *ReadSize = UsedSize - OffsetAdjustment;
2676 }
2677 else
2678 {
2679 ExFreePool(Buffer);
2680 }
2681
2682 return Status;
2683 }
2684
2685 #ifdef NASSERT
2686 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2687 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2688 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2689 #else
2690 static
2691 VOID
2692 NTAPI
2693 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2694 {
2695 ULONG i;
2696
2697 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
2698 {
2699 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
2700 ImageSectionObject->Segments[i - 1].VirtualAddress);
2701 }
2702 }
2703
2704 static
2705 VOID
2706 NTAPI
2707 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2708 {
2709 ULONG i;
2710
2711 MmspAssertSegmentsSorted(ImageSectionObject);
2712
2713 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2714 {
2715 ASSERT(ImageSectionObject->Segments[i].Length > 0);
2716
2717 if(i > 0)
2718 {
2719 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
2720 (ImageSectionObject->Segments[i - 1].VirtualAddress +
2721 ImageSectionObject->Segments[i - 1].Length));
2722 }
2723 }
2724 }
2725
2726 static
2727 VOID
2728 NTAPI
2729 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2730 {
2731 ULONG i;
2732
2733 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2734 {
2735 ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
2736 ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
2737 }
2738 }
2739 #endif
2740
2741 static
2742 int
2743 __cdecl
2744 MmspCompareSegments(const void * x,
2745 const void * y)
2746 {
2747 PMM_SECTION_SEGMENT Segment1 = (PMM_SECTION_SEGMENT)x;
2748 PMM_SECTION_SEGMENT Segment2 = (PMM_SECTION_SEGMENT)y;
2749
2750 return
2751 (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
2752 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
2753 }
2754
2755 /*
2756 * Ensures an image section's segments are sorted in memory
2757 */
2758 static
2759 VOID
2760 NTAPI
2761 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2762 IN ULONG Flags)
2763 {
2764 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
2765 {
2766 MmspAssertSegmentsSorted(ImageSectionObject);
2767 }
2768 else
2769 {
2770 qsort(ImageSectionObject->Segments,
2771 ImageSectionObject->NrSegments,
2772 sizeof(ImageSectionObject->Segments[0]),
2773 MmspCompareSegments);
2774 }
2775 }
2776
2777
2778 /*
2779 * Ensures an image section's segments don't overlap in memory and don't have
2780 * gaps and don't have a null size. We let them map to overlapping file regions,
2781 * though - that's not necessarily an error
2782 */
2783 static
2784 BOOLEAN
2785 NTAPI
2786 MmspCheckSegmentBounds
2787 (
2788 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2789 IN ULONG Flags
2790 )
2791 {
2792 ULONG i;
2793
2794 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
2795 {
2796 MmspAssertSegmentsNoOverlap(ImageSectionObject);
2797 return TRUE;
2798 }
2799
2800 ASSERT(ImageSectionObject->NrSegments >= 1);
2801
2802 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2803 {
2804 if(ImageSectionObject->Segments[i].Length == 0)
2805 {
2806 return FALSE;
2807 }
2808
2809 if(i > 0)
2810 {
2811 /*
2812 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2813 * page could be OK (Windows seems to be OK with them), and larger gaps
2814 * could lead to image sections spanning several discontiguous regions
2815 * (NtMapViewOfSection could then refuse to map them, and they could
2816 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2817 */
2818 if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
2819 ImageSectionObject->Segments[i - 1].Length) !=
2820 ImageSectionObject->Segments[i].VirtualAddress)
2821 {
2822 return FALSE;
2823 }
2824 }
2825 }
2826
2827 return TRUE;
2828 }
2829
2830 /*
2831 * Merges and pads an image section's segments until they all are page-aligned
2832 * and have a size that is a multiple of the page size
2833 */
2834 static
2835 BOOLEAN
2836 NTAPI
2837 MmspPageAlignSegments
2838 (
2839 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2840 IN ULONG Flags
2841 )
2842 {
2843 ULONG i;
2844 ULONG LastSegment;
2845 BOOLEAN Initialized;
2846 PMM_SECTION_SEGMENT EffectiveSegment;
2847
2848 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
2849 {
2850 MmspAssertSegmentsPageAligned(ImageSectionObject);
2851 return TRUE;
2852 }
2853
2854 Initialized = FALSE;
2855 LastSegment = 0;
2856 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2857
2858 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2859 {
2860 /*
2861 * The first segment requires special handling
2862 */
2863 if (i == 0)
2864 {
2865 ULONG_PTR VirtualAddress;
2866 ULONG_PTR VirtualOffset;
2867
2868 VirtualAddress = EffectiveSegment->VirtualAddress;
2869
2870 /* Round down the virtual address to the nearest page */
2871 EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
2872
2873 /* Round up the virtual size to the nearest page */
2874 EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
2875 EffectiveSegment->VirtualAddress;
2876
2877 /* Adjust the raw address and size */
2878 VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
2879
2880 if (EffectiveSegment->FileOffset < VirtualOffset)
2881 {
2882 return FALSE;
2883 }
2884
2885 /*
2886 * Garbage in, garbage out: unaligned base addresses make the file
2887 * offset point in curious and odd places, but that's what we were
2888 * asked for
2889 */
2890 EffectiveSegment->FileOffset -= VirtualOffset;
2891 EffectiveSegment->RawLength += VirtualOffset;
2892 }
2893 else
2894 {
2895 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
2896 ULONG_PTR EndOfEffectiveSegment;
2897
2898 EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
2899 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
2900
2901 /*
2902 * The current segment begins exactly where the current effective
2903 * segment ended, therefore beginning a new effective segment
2904 */
2905 if (EndOfEffectiveSegment == Segment->VirtualAddress)
2906 {
2907 LastSegment ++;
2908 ASSERT(LastSegment <= i);
2909 ASSERT(LastSegment < ImageSectionObject->NrSegments);
2910
2911 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2912
2913 if (LastSegment != i)
2914 {
2915 /*
2916 * Copy the current segment. If necessary, the effective segment
2917 * will be expanded later
2918 */
2919 *EffectiveSegment = *Segment;
2920 }
2921
2922 /*
2923 * Page-align the virtual size. We know for sure the virtual address
2924 * already is
2925 */
2926 ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
2927 EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
2928 }
2929 /*
2930 * The current segment is still part of the current effective segment:
2931 * extend the effective segment to reflect this
2932 */
2933 else if (EndOfEffectiveSegment > Segment->VirtualAddress)
2934 {
2935 static const ULONG FlagsToProtection[16] =
2936 {
2937 PAGE_NOACCESS,
2938 PAGE_READONLY,
2939 PAGE_READWRITE,
2940 PAGE_READWRITE,
2941 PAGE_EXECUTE_READ,
2942 PAGE_EXECUTE_READ,
2943 PAGE_EXECUTE_READWRITE,
2944 PAGE_EXECUTE_READWRITE,
2945 PAGE_WRITECOPY,
2946 PAGE_WRITECOPY,
2947 PAGE_WRITECOPY,
2948 PAGE_WRITECOPY,
2949 PAGE_EXECUTE_WRITECOPY,
2950 PAGE_EXECUTE_WRITECOPY,
2951 PAGE_EXECUTE_WRITECOPY,
2952 PAGE_EXECUTE_WRITECOPY
2953 };
2954
2955 unsigned ProtectionFlags;
2956
2957 /*
2958 * Extend the file size
2959 */
2960
2961 /* Unaligned segments must be contiguous within the file */
2962 if (Segment->FileOffset != (EffectiveSegment->FileOffset +
2963 EffectiveSegment->RawLength))
2964 {
2965 return FALSE;
2966 }
2967
2968 EffectiveSegment->RawLength += Segment->RawLength;
2969
2970 /*
2971 * Extend the virtual size
2972 */
2973 ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
2974
2975 EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
2976 EffectiveSegment->VirtualAddress;
2977
2978 /*
2979 * Merge the protection
2980 */
2981 EffectiveSegment->Protection |= Segment->Protection;
2982
2983 /* Clean up redundance */
2984 ProtectionFlags = 0;
2985
2986 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
2987 ProtectionFlags |= 1 << 0;
2988
2989 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
2990 ProtectionFlags |= 1 << 1;
2991
2992 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
2993 ProtectionFlags |= 1 << 2;
2994
2995 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
2996 ProtectionFlags |= 1 << 3;
2997
2998 ASSERT(ProtectionFlags < 16);
2999 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3000
3001 /* If a segment was required to be shared and cannot, fail */
3002 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3003 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3004 {
3005 return FALSE;
3006 }
3007 }
3008 /*
3009 * We assume no holes between segments at this point
3010 */
3011 else
3012 {
3013 ASSERT(FALSE);
3014 }
3015 }
3016 }
3017 ImageSectionObject->NrSegments = LastSegment + 1;
3018
3019 return TRUE;
3020 }
3021
3022 NTSTATUS
3023 ExeFmtpCreateImageSection(HANDLE FileHandle,
3024 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3025 {
3026 LARGE_INTEGER Offset;
3027 PVOID FileHeader;
3028 PVOID FileHeaderBuffer;
3029 ULONG FileHeaderSize;
3030 ULONG Flags;
3031 ULONG OldNrSegments;
3032 NTSTATUS Status;
3033 ULONG i;
3034
3035 /*
3036 * Read the beginning of the file (2 pages). Should be enough to contain
3037 * all (or most) of the headers
3038 */
3039 Offset.QuadPart = 0;
3040
3041 /* FIXME: use FileObject instead of FileHandle */
3042 Status = ExeFmtpReadFile (FileHandle,
3043 &Offset,
3044 PAGE_SIZE * 2,
3045 &FileHeader,
3046 &FileHeaderBuffer,
3047 &FileHeaderSize);
3048
3049 if (!NT_SUCCESS(Status))
3050 return Status;
3051
3052 if (FileHeaderSize == 0)
3053 {
3054 ExFreePool(FileHeaderBuffer);
3055 return STATUS_UNSUCCESSFUL;
3056 }
3057
3058 /*
3059 * Look for a loader that can handle this executable
3060 */
3061 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3062 {
3063 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3064 Flags = 0;
3065
3066 /* FIXME: use FileObject instead of FileHandle */
3067 Status = ExeFmtpLoaders[i](FileHeader,
3068 FileHeaderSize,
3069 FileHandle,
3070 ImageSectionObject,
3071 &Flags,
3072 ExeFmtpReadFile,
3073 ExeFmtpAllocateSegments);
3074
3075 if (!NT_SUCCESS(Status))
3076 {
3077 if (ImageSectionObject->Segments)
3078 {
3079 ExFreePool(ImageSectionObject->Segments);
3080 ImageSectionObject->Segments = NULL;
3081 }
3082 }
3083
3084 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3085 break;
3086 }
3087
3088 ExFreePool(FileHeaderBuffer);
3089
3090 /*
3091 * No loader handled the format
3092 */
3093 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3094 {
3095 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3096 ASSERT(!NT_SUCCESS(Status));
3097 }
3098
3099 if (!NT_SUCCESS(Status))
3100 return Status;
3101
3102 ASSERT(ImageSectionObject->Segments != NULL);
3103
3104 /*
3105 * Some defaults
3106 */
3107 /* FIXME? are these values platform-dependent? */
3108 if(ImageSectionObject->StackReserve == 0)
3109 ImageSectionObject->StackReserve = 0x40000;
3110
3111 if(ImageSectionObject->StackCommit == 0)
3112 ImageSectionObject->StackCommit = 0x1000;
3113
3114 if(ImageSectionObject->ImageBase == 0)
3115 {
3116 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3117 ImageSectionObject->ImageBase = 0x10000000;
3118 else
3119 ImageSectionObject->ImageBase = 0x00400000;
3120 }
3121
3122 /*
3123 * And now the fun part: fixing the segments
3124 */
3125
3126 /* Sort them by virtual address */
3127 MmspSortSegments(ImageSectionObject, Flags);
3128
3129 /* Ensure they don't overlap in memory */
3130 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3131 return STATUS_INVALID_IMAGE_FORMAT;
3132
3133 /* Ensure they are aligned */
3134 OldNrSegments = ImageSectionObject->NrSegments;
3135
3136 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3137 return STATUS_INVALID_IMAGE_FORMAT;
3138
3139 /* Trim them if the alignment phase merged some of them */
3140 if (ImageSectionObject->NrSegments < OldNrSegments)
3141 {
3142 PMM_SECTION_SEGMENT Segments;
3143 SIZE_T SizeOfSegments;
3144
3145 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3146
3147 Segments = ExAllocatePoolWithTag(PagedPool,
3148 SizeOfSegments,
3149 TAG_MM_SECTION_SEGMENT);
3150
3151 if (Segments == NULL)
3152 return STATUS_INSUFFICIENT_RESOURCES;
3153
3154 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3155 ExFreePool(ImageSectionObject->Segments);
3156 ImageSectionObject->Segments = Segments;
3157 }
3158
3159 /* And finish their initialization */
3160 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3161 {
3162 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3163 ImageSectionObject->Segments[i].ReferenceCount = 1;
3164
3165 RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
3166 sizeof(ImageSectionObject->Segments[i].PageDirectory));
3167 }
3168
3169 ASSERT(NT_SUCCESS(Status));
3170 return Status;
3171 }
3172
3173 NTSTATUS
3174 MmCreateImageSection(PSECTION_OBJECT *SectionObject,
3175 ACCESS_MASK DesiredAccess,
3176 POBJECT_ATTRIBUTES ObjectAttributes,
3177 PLARGE_INTEGER UMaximumSize,
3178 ULONG SectionPageProtection,
3179 ULONG AllocationAttributes,
3180 HANDLE FileHandle)
3181 {
3182 PSECTION_OBJECT Section;
3183 NTSTATUS Status;
3184 PFILE_OBJECT FileObject;
3185 PMM_SECTION_SEGMENT SectionSegments;
3186 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3187 ULONG i;
3188 ULONG FileAccess = 0;
3189
3190 /*
3191 * Specifying a maximum size is meaningless for an image section
3192 */
3193 if (UMaximumSize != NULL)
3194 {
3195 return(STATUS_INVALID_PARAMETER_4);
3196 }
3197
3198 /*
3199 * Check file access required
3200 */
3201 if (SectionPageProtection & PAGE_READWRITE ||
3202 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3203 {
3204 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3205 }
3206 else
3207 {
3208 FileAccess = FILE_READ_DATA;
3209 }
3210
3211 /*
3212 * Reference the file handle
3213 */
3214 Status = ObReferenceObjectByHandle(FileHandle,
3215 FileAccess,
3216 IoFileObjectType,
3217 UserMode,
3218 (PVOID*)(PVOID)&FileObject,
3219 NULL);
3220
3221 if (!NT_SUCCESS(Status))
3222 {
3223 return Status;
3224 }
3225
3226 /*
3227 * Create the section
3228 */
3229 Status = ObCreateObject (ExGetPreviousMode(),
3230 MmSectionObjectType,
3231 ObjectAttributes,
3232 ExGetPreviousMode(),
3233 NULL,
3234 sizeof(SECTION_OBJECT),
3235 0,
3236 0,
3237 (PVOID*)(PVOID)&Section);
3238 if (!NT_SUCCESS(Status))
3239 {
3240 ObDereferenceObject(FileObject);
3241 return(Status);
3242 }
3243
3244 /*
3245 * Initialize it
3246 */
3247 Section->SectionPageProtection = SectionPageProtection;
3248 Section->AllocationAttributes = AllocationAttributes;
3249
3250 /*
3251 * Initialized caching for this file object if previously caching
3252 * was initialized for the same on disk file
3253 */
3254 Status = CcTryToInitializeFileCache(FileObject);
3255
3256 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3257 {
3258 NTSTATUS StatusExeFmt;
3259
3260 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3261 if (ImageSectionObject == NULL)
3262 {
3263 ObDereferenceObject(FileObject);
3264 ObDereferenceObject(Section);
3265 return(STATUS_NO_MEMORY);
3266 }
3267
3268 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3269
3270 StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
3271
3272 if (!NT_SUCCESS(StatusExeFmt))
3273 {
3274 if(ImageSectionObject->Segments != NULL)
3275 ExFreePool(ImageSectionObject->Segments);
3276
3277 ExFreePool(ImageSectionObject);
3278 ObDereferenceObject(Section);
3279 ObDereferenceObject(FileObject);
3280 return(StatusExeFmt);
3281 }
3282
3283 Section->ImageSection = ImageSectionObject;
3284 ASSERT(ImageSectionObject->Segments);
3285
3286 /*
3287 * Lock the file
3288 */
3289 Status = MmspWaitForFileLock(FileObject);
3290 if (!NT_SUCCESS(Status))
3291 {
3292 ExFreePool(ImageSectionObject->Segments);
3293 ExFreePool(ImageSectionObject);
3294 ObDereferenceObject(Section);
3295 ObDereferenceObject(FileObject);
3296 return(Status);
3297 }
3298
3299 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3300 ImageSectionObject, NULL))
3301 {
3302 /*
3303 * An other thread has initialized the some image in the background
3304 */
3305 ExFreePool(ImageSectionObject->Segments);
3306 ExFreePool(ImageSectionObject);
3307 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3308 Section->ImageSection = ImageSectionObject;
3309 SectionSegments = ImageSectionObject->Segments;
3310
3311 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3312 {
3313 InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3314 }
3315 }
3316
3317 Status = StatusExeFmt;
3318 }
3319 else
3320 {
3321 /*
3322 * Lock the file
3323 */
3324 Status = MmspWaitForFileLock(FileObject);
3325 if (Status != STATUS_SUCCESS)
3326 {
3327 ObDereferenceObject(Section);
3328 ObDereferenceObject(FileObject);
3329 return(Status);
3330 }
3331
3332 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3333 Section->ImageSection = ImageSectionObject;
3334 SectionSegments = ImageSectionObject->Segments;
3335
3336 /*
3337 * Otherwise just reference all the section segments
3338 */
3339 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3340 {
3341 InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3342 }
3343
3344 Status = STATUS_SUCCESS;
3345 }
3346 Section->FileObject = FileObject;
3347 CcRosReferenceCache(FileObject);
3348 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3349 *SectionObject = Section;
3350 return(Status);
3351 }
3352
3353 /*
3354 * @implemented
3355 */
3356 NTSTATUS STDCALL
3357 NtCreateSection (OUT PHANDLE SectionHandle,
3358 IN ACCESS_MASK DesiredAccess,
3359 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3360 IN PLARGE_INTEGER MaximumSize OPTIONAL,
3361 IN ULONG SectionPageProtection OPTIONAL,
3362 IN ULONG AllocationAttributes,
3363 IN HANDLE FileHandle OPTIONAL)
3364 {
3365 LARGE_INTEGER SafeMaximumSize;
3366 PSECTION_OBJECT SectionObject;
3367 KPROCESSOR_MODE PreviousMode;
3368 NTSTATUS Status = STATUS_SUCCESS;
3369
3370 PreviousMode = ExGetPreviousMode();
3371
3372 if(MaximumSize != NULL && PreviousMode != KernelMode)
3373 {
3374 _SEH_TRY
3375 {
3376 /* make a copy on the stack */
3377 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
3378 MaximumSize = &SafeMaximumSize;
3379 }
3380 _SEH_HANDLE
3381 {
3382 Status = _SEH_GetExceptionCode();
3383 }
3384 _SEH_END;
3385
3386 if(!NT_SUCCESS(Status))
3387 {
3388 return Status;
3389 }
3390 }
3391
3392 Status = MmCreateSection(&SectionObject,
3393 DesiredAccess,
3394 ObjectAttributes,
3395 MaximumSize,
3396 SectionPageProtection,
3397 AllocationAttributes,
3398 FileHandle,
3399 NULL);
3400
3401 if (NT_SUCCESS(Status))
3402 {
3403 Status = ObInsertObject ((PVOID)SectionObject,
3404 NULL,
3405 DesiredAccess,
3406 0,
3407 NULL,
3408 SectionHandle);
3409 ObDereferenceObject(SectionObject);
3410 }
3411
3412 return Status;
3413 }
3414
3415
3416 /**********************************************************************
3417 * NAME
3418 * NtOpenSection
3419 *
3420 * DESCRIPTION
3421 *
3422 * ARGUMENTS
3423 * SectionHandle
3424 *
3425 * DesiredAccess
3426 *
3427 * ObjectAttributes
3428 *
3429 * RETURN VALUE
3430 *
3431 * REVISIONS
3432 */
3433 NTSTATUS STDCALL
3434 NtOpenSection(PHANDLE SectionHandle,
3435 ACCESS_MASK DesiredAccess,
3436 POBJECT_ATTRIBUTES ObjectAttributes)
3437 {
3438 HANDLE hSection;
3439 KPROCESSOR_MODE PreviousMode;
3440 NTSTATUS Status = STATUS_SUCCESS;
3441
3442 PreviousMode = ExGetPreviousMode();
3443
3444 if(PreviousMode != KernelMode)
3445 {
3446 _SEH_TRY
3447 {
3448 ProbeForWriteHandle(SectionHandle);
3449 }
3450 _SEH_HANDLE
3451 {
3452 Status = _SEH_GetExceptionCode();
3453 }
3454 _SEH_END;
3455
3456 if(!NT_SUCCESS(Status))
3457 {
3458 return Status;
3459 }
3460 }
3461
3462 Status = ObOpenObjectByName(ObjectAttributes,
3463 MmSectionObjectType,
3464 NULL,
3465 PreviousMode,
3466 DesiredAccess,
3467 NULL,
3468 &hSection);
3469
3470 if(NT_SUCCESS(Status))
3471 {
3472 _SEH_TRY
3473 {
3474 *SectionHandle = hSection;
3475 }
3476 _SEH_HANDLE
3477 {
3478 Status = _SEH_GetExceptionCode();
3479 }
3480 _SEH_END;
3481 }
3482
3483 return(Status);
3484 }
3485
3486 NTSTATUS STATIC
3487 MmMapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3488 PSECTION_OBJECT Section,
3489 PMM_SECTION_SEGMENT Segment,
3490 PVOID* BaseAddress,
3491 ULONG ViewSize,
3492 ULONG Protect,
3493 ULONG ViewOffset,
3494 ULONG AllocationType)
3495 {
3496 PMEMORY_AREA MArea;
3497 NTSTATUS Status;
3498 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3499
3500 BoundaryAddressMultiple.QuadPart = 0;
3501
3502 Status = MmCreateMemoryArea(AddressSpace,
3503 MEMORY_AREA_SECTION_VIEW,
3504 BaseAddress,
3505 ViewSize,
3506 Protect,
3507 &MArea,
3508 FALSE,
3509 AllocationType,
3510 BoundaryAddressMultiple);
3511 if (!NT_SUCCESS(Status))
3512 {
3513 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3514 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3515 return(Status);
3516 }
3517
3518 ObReferenceObject((PVOID)Section);
3519
3520 MArea->Data.SectionData.Segment = Segment;
3521 MArea->Data.SectionData.Section = Section;
3522 MArea->Data.SectionData.ViewOffset = ViewOffset;
3523 MArea->Data.SectionData.WriteCopyView = FALSE;
3524 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
3525 ViewSize, 0, Protect);
3526
3527 return(STATUS_SUCCESS);
3528 }
3529
3530
3531 /**********************************************************************
3532 * NAME EXPORTED
3533 * NtMapViewOfSection
3534 *
3535 * DESCRIPTION
3536 * Maps a view of a section into the virtual address space of a
3537 * process.
3538 *
3539 * ARGUMENTS
3540 * SectionHandle
3541 * Handle of the section.
3542 *
3543 * ProcessHandle
3544 * Handle of the process.
3545 *
3546 * BaseAddress
3547 * Desired base address (or NULL) on entry;
3548 * Actual base address of the view on exit.
3549 *
3550 * ZeroBits
3551 * Number of high order address bits that must be zero.
3552 *
3553 * CommitSize
3554 * Size in bytes of the initially committed section of
3555 * the view.
3556 *
3557 * SectionOffset
3558 * Offset in bytes from the beginning of the section
3559 * to the beginning of the view.
3560 *
3561 * ViewSize
3562 * Desired length of map (or zero to map all) on entry
3563 * Actual length mapped on exit.
3564 *
3565 * InheritDisposition
3566 * Specified how the view is to be shared with
3567 * child processes.
3568 *
3569 * AllocateType
3570 * Type of allocation for the pages.
3571 *
3572 * Protect
3573 * Protection for the committed region of the view.
3574 *
3575 * RETURN VALUE
3576 * Status.
3577 *
3578 * @implemented
3579 */
3580 NTSTATUS STDCALL
3581 NtMapViewOfSection(IN HANDLE SectionHandle,
3582 IN HANDLE ProcessHandle,
3583 IN OUT PVOID* BaseAddress OPTIONAL,
3584 IN ULONG ZeroBits OPTIONAL,
3585 IN ULONG CommitSize,
3586 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3587 IN OUT PULONG ViewSize,
3588 IN SECTION_INHERIT InheritDisposition,
3589 IN ULONG AllocationType OPTIONAL,
3590 IN ULONG Protect)
3591 {
3592 PVOID SafeBaseAddress;
3593 LARGE_INTEGER SafeSectionOffset;
3594 ULONG SafeViewSize;
3595 PSECTION_OBJECT Section;
3596 PEPROCESS Process;
3597 KPROCESSOR_MODE PreviousMode;
3598 PMADDRESS_SPACE AddressSpace;
3599 NTSTATUS Status = STATUS_SUCCESS;
3600 ULONG tmpProtect;
3601
3602 /*
3603 * Check the protection
3604 */
3605 if (Protect & ~PAGE_FLAGS_VALID_FROM_USER_MODE)
3606 {
3607 CHECKPOINT1;
3608 return STATUS_INVALID_PARAMETER_10;
3609 }
3610
3611 tmpProtect = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
3612 if (tmpProtect != PAGE_NOACCESS &&
3613 tmpProtect != PAGE_READONLY &&
3614 tmpProtect != PAGE_READWRITE &&
3615 tmpProtect != PAGE_WRITECOPY &&
3616 tmpProtect != PAGE_EXECUTE &&
3617 tmpProtect != PAGE_EXECUTE_READ &&
3618 tmpProtect != PAGE_EXECUTE_READWRITE &&
3619 tmpProtect != PAGE_EXECUTE_WRITECOPY)
3620 {
3621 CHECKPOINT1;
3622 return STATUS_INVALID_PAGE_PROTECTION;
3623 }
3624
3625 PreviousMode = ExGetPreviousMode();
3626
3627 if(PreviousMode != KernelMode)
3628 {
3629 SafeBaseAddress = NULL;
3630 SafeSectionOffset.QuadPart = 0;
3631 SafeViewSize = 0;
3632
3633 _SEH_TRY
3634 {
3635 if(BaseAddress != NULL)
3636 {
3637 ProbeForWritePointer(BaseAddress);
3638 SafeBaseAddress = *BaseAddress;
3639 }
3640 if(SectionOffset != NULL)
3641 {
3642 ProbeForWriteLargeInteger(SectionOffset);
3643 SafeSectionOffset = *SectionOffset;
3644 }
3645 ProbeForWriteUlong(ViewSize);
3646 SafeViewSize = *ViewSize;
3647 }
3648 _SEH_HANDLE
3649 {
3650 Status = _SEH_GetExceptionCode();
3651 }
3652 _SEH_END;
3653
3654 if(!NT_SUCCESS(Status))
3655 {
3656 return Status;
3657 }
3658 }
3659 else
3660 {
3661 SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
3662 SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
3663 SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
3664 }
3665
3666 Status = ObReferenceObjectByHandle(ProcessHandle,
3667 PROCESS_VM_OPERATION,
3668 PsProcessType,
3669 PreviousMode,
3670 (PVOID*)(PVOID)&Process,
3671 NULL);
3672 if (!NT_SUCCESS(Status))
3673 {
3674 return(Status);
3675 }
3676
3677 AddressSpace = &Process->AddressSpace;
3678
3679 Status = ObReferenceObjectByHandle(SectionHandle,
3680 SECTION_MAP_READ,
3681 MmSectionObjectType,
3682 PreviousMode,
3683 (PVOID*)(PVOID)&Section,
3684 NULL);
3685 if (!(NT_SUCCESS(Status)))
3686 {
3687 DPRINT("ObReference failed rc=%x\n",Status);
3688 ObDereferenceObject(Process);
3689 return(Status);
3690 }
3691
3692 Status = MmMapViewOfSection(Section,
3693 Process,
3694 (BaseAddress != NULL ? &SafeBaseAddress : NULL),
3695 ZeroBits,
3696 CommitSize,
3697 (SectionOffset != NULL ? &SafeSectionOffset : NULL),
3698 (ViewSize != NULL ? &SafeViewSize : NULL),
3699 InheritDisposition,
3700 AllocationType,
3701 Protect);
3702
3703 ObDereferenceObject(Section);
3704 ObDereferenceObject(Process);
3705
3706 if(NT_SUCCESS(Status))
3707 {
3708 /* copy parameters back to the caller */
3709 _SEH_TRY
3710 {
3711 if(BaseAddress != NULL)
3712 {
3713 *BaseAddress = SafeBaseAddress;
3714 }
3715 if(SectionOffset != NULL)
3716 {
3717 *SectionOffset = SafeSectionOffset;
3718 }
3719 if(ViewSize != NULL)
3720 {
3721 *ViewSize = SafeViewSize;
3722 }
3723 }
3724 _SEH_HANDLE
3725 {
3726 Status = _SEH_GetExceptionCode();
3727 }
3728 _SEH_END;
3729 }
3730
3731 return(Status);
3732 }
3733
3734 VOID STATIC
3735 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3736 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3737 {
3738 ULONG Entry;
3739 PFILE_OBJECT FileObject;
3740 PBCB Bcb;
3741 ULONG Offset;
3742 SWAPENTRY SavedSwapEntry;
3743 PMM_PAGEOP PageOp;
3744 NTSTATUS Status;
3745 PSECTION_OBJECT Section;
3746 PMM_SECTION_SEGMENT Segment;
3747 PMADDRESS_SPACE AddressSpace;
3748
3749 AddressSpace = (PMADDRESS_SPACE)Context;
3750
3751 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3752
3753 Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
3754 MemoryArea->Data.SectionData.ViewOffset;
3755
3756 Section = MemoryArea->Data.SectionData.Section;
3757 Segment = MemoryArea->Data.SectionData.Segment;
3758
3759 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3760
3761 while (PageOp)
3762 {
3763 MmUnlockSectionSegment(Segment);
3764 MmUnlockAddressSpace(AddressSpace);
3765
3766 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3767 if (Status != STATUS_SUCCESS)
3768 {
3769 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3770 KEBUGCHECK(0);
3771 }
3772
3773 MmLockAddressSpace(AddressSpace);
3774 MmLockSectionSegment(Segment);
3775 MmspCompleteAndReleasePageOp(PageOp);
3776 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3777 }
3778
3779 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3780
3781 /*
3782 * For a dirty, datafile, non-private page mark it as dirty in the
3783 * cache manager.
3784 */
3785 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3786 {
3787 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3788 {
3789 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3790 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3791 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
3792 ASSERT(SwapEntry == 0);
3793 }
3794 }
3795
3796 if (SwapEntry != 0)
3797 {
3798 /*
3799 * Sanity check
3800 */
3801 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3802 {
3803 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3804 KEBUGCHECK(0);
3805 }
3806 MmFreeSwapPage(SwapEntry);
3807 }
3808 else if (Page != 0)
3809 {
3810 if (IS_SWAP_FROM_SSE(Entry) ||
3811 Page != PFN_FROM_SSE(Entry))
3812 {
3813 /*
3814 * Sanity check
3815 */
3816 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3817 {
3818 DPRINT1("Found a private page in a pagefile section.\n");
3819 KEBUGCHECK(0);
3820 }
3821 /*
3822 * Just dereference private pages
3823 */
3824 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3825 if (SavedSwapEntry != 0)
3826 {
3827 MmFreeSwapPage(SavedSwapEntry);
3828 MmSetSavedSwapEntryPage(Page, 0);
3829 }
3830 MmDeleteRmap(Page, AddressSpace->Process, Address);
3831 MmReleasePageMemoryConsumer(MC_USER, Page);
3832 }
3833 else
3834 {
3835 MmDeleteRmap(Page, AddressSpace->Process, Address);
3836 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3837 }
3838 }
3839 }
3840
3841 STATIC NTSTATUS
3842 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3843 PVOID BaseAddress)
3844 {
3845 NTSTATUS Status;
3846 PMEMORY_AREA MemoryArea;
3847 PSECTION_OBJECT Section;
3848 PMM_SECTION_SEGMENT Segment;
3849 PLIST_ENTRY CurrentEntry;
3850 PMM_REGION CurrentRegion;
3851 PLIST_ENTRY RegionListHead;
3852
3853 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3854 BaseAddress);
3855 if (MemoryArea == NULL)
3856 {
3857 return(STATUS_UNSUCCESSFUL);
3858 }
3859
3860 MemoryArea->DeleteInProgress = TRUE;
3861 Section = MemoryArea->Data.SectionData.Section;
3862 Segment = MemoryArea->Data.SectionData.Segment;
3863
3864 MmLockSectionSegment(Segment);
3865
3866 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3867 while (!IsListEmpty(RegionListHead))
3868 {
3869 CurrentEntry = RemoveHeadList(RegionListHead);
3870 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3871 ExFreePool(CurrentRegion);
3872 }
3873
3874 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3875 {
3876 Status = MmFreeMemoryArea(AddressSpace,
3877 MemoryArea,
3878 NULL,
3879 NULL);
3880 }
3881 else
3882 {
3883 Status = MmFreeMemoryArea(AddressSpace,
3884 MemoryArea,
3885 MmFreeSectionPage,
3886 AddressSpace);
3887 }
3888 MmUnlockSectionSegment(Segment);
3889 ObDereferenceObject(Section);
3890 return(STATUS_SUCCESS);
3891 }
3892
3893 /*
3894 * @implemented
3895 */
3896 NTSTATUS STDCALL
3897 MmUnmapViewOfSection(PEPROCESS Process,
3898 PVOID BaseAddress)
3899 {
3900 NTSTATUS Status;
3901 PMEMORY_AREA MemoryArea;
3902 PMADDRESS_SPACE AddressSpace;
3903 PSECTION_OBJECT Section;
3904 PMM_PAGEOP PageOp;
3905 ULONG_PTR Offset;
3906
3907 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3908 Process, BaseAddress);
3909
3910 ASSERT(Process);
3911
3912 AddressSpace = &Process->AddressSpace;
3913
3914 MmLockAddressSpace(AddressSpace);
3915 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3916 BaseAddress);
3917 if (MemoryArea == NULL ||
3918 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
3919 MemoryArea->DeleteInProgress)
3920 {
3921 MmUnlockAddressSpace(AddressSpace);
3922 return STATUS_NOT_MAPPED_VIEW;
3923 }
3924
3925 MemoryArea->DeleteInProgress = TRUE;
3926
3927 while (MemoryArea->PageOpCount)
3928 {
3929 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
3930
3931 while (Offset)
3932 {
3933 Offset -= PAGE_SIZE;
3934 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
3935 MemoryArea->Data.SectionData.Segment,
3936 Offset + MemoryArea->Data.SectionData.ViewOffset);
3937 if (PageOp)
3938 {
3939 MmUnlockAddressSpace(AddressSpace);
3940 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3941 if (Status != STATUS_SUCCESS)
3942 {
3943 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3944 KEBUGCHECK(0);
3945 }
3946 MmLockAddressSpace(AddressSpace);
3947 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3948 BaseAddress);
3949 if (MemoryArea == NULL ||
3950 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
3951 {
3952 MmUnlockAddressSpace(AddressSpace);
3953 return STATUS_NOT_MAPPED_VIEW;
3954 }
3955 break;
3956 }
3957 }
3958 }
3959
3960 Section = MemoryArea->Data.SectionData.Section;
3961
3962 if (Section->AllocationAttributes & SEC_IMAGE)
3963 {
3964 ULONG i;
3965 ULONG NrSegments;
3966 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3967 PMM_SECTION_SEGMENT SectionSegments;
3968 PVOID ImageBaseAddress = 0;
3969 PMM_SECTION_SEGMENT Segment;
3970
3971 Segment = MemoryArea->Data.SectionData.Segment;
3972 ImageSectionObject = Section->ImageSection;
3973 SectionSegments = ImageSectionObject->Segments;
3974 NrSegments = ImageSectionObject->NrSegments;
3975
3976 /* Search for the current segment within the section segments
3977 * and calculate the image base address */
3978 for (i = 0; i < NrSegments; i++)
3979 {
3980 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
3981 {
3982 if (Segment == &SectionSegments[i])
3983 {
3984 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
3985 break;
3986 }
3987 }
3988 }
3989 if (i >= NrSegments)
3990 {
3991 KEBUGCHECK(0);
3992 }
3993
3994 for (i = 0; i < NrSegments; i++)
3995 {
3996 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
3997 {
3998 PVOID SBaseAddress = (PVOID)
3999 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4000
4001 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4002 }
4003 }
4004 }
4005 else
4006 {
4007 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4008 }
4009 MmUnlockAddressSpace(AddressSpace);
4010 return(STATUS_SUCCESS);
4011 }
4012
4013 /**********************************************************************
4014 * NAME EXPORTED
4015 * NtUnmapViewOfSection
4016 *
4017 * DESCRIPTION
4018 *
4019 * ARGUMENTS
4020 * ProcessHandle
4021 *
4022 * BaseAddress
4023 *
4024 * RETURN VALUE
4025 * Status.
4026 *
4027 * REVISIONS
4028 */
4029 NTSTATUS STDCALL
4030 NtUnmapViewOfSection (HANDLE ProcessHandle,
4031 PVOID BaseAddress)
4032 {
4033 PEPROCESS Process;
4034 KPROCESSOR_MODE PreviousMode;
4035 NTSTATUS Status;
4036
4037 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4038 ProcessHandle, BaseAddress);
4039
4040 PreviousMode = ExGetPreviousMode();
4041
4042 DPRINT("Referencing process\n");
4043 Status = ObReferenceObjectByHandle(ProcessHandle,
4044 PROCESS_VM_OPERATION,
4045 PsProcessType,
4046 PreviousMode,
4047 (PVOID*)(PVOID)&Process,
4048 NULL);
4049 if (!NT_SUCCESS(Status))
4050 {
4051 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
4052 return(Status);
4053 }
4054
4055 Status = MmUnmapViewOfSection(Process, BaseAddress);
4056
4057 ObDereferenceObject(Process);
4058
4059 return Status;
4060 }
4061
4062
4063 /**
4064 * Queries the information of a section object.
4065 *
4066 * @param SectionHandle
4067 * Handle to the section object. It must be opened with SECTION_QUERY
4068 * access.
4069 * @param SectionInformationClass
4070 * Index to a certain information structure. Can be either
4071 * SectionBasicInformation or SectionImageInformation. The latter
4072 * is valid only for sections that were created with the SEC_IMAGE
4073 * flag.
4074 * @param SectionInformation
4075 * Caller supplies storage for resulting information.
4076 * @param Length
4077 * Size of the supplied storage.
4078 * @param ResultLength
4079 * Data written.
4080 *
4081 * @return Status.
4082 *
4083 * @implemented
4084 */
4085 NTSTATUS STDCALL
4086 NtQuerySection(IN HANDLE SectionHandle,
4087 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4088 OUT PVOID SectionInformation,
4089 IN ULONG SectionInformationLength,
4090 OUT PULONG ResultLength OPTIONAL)
4091 {
4092 PSECTION_OBJECT Section;
4093 KPROCESSOR_MODE PreviousMode;
4094 NTSTATUS Status = STATUS_SUCCESS;
4095
4096 PreviousMode = ExGetPreviousMode();
4097
4098 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4099 ExSectionInfoClass,
4100 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4101 SectionInformation,
4102 SectionInformationLength,
4103 ResultLength,
4104 PreviousMode);
4105
4106 if(!NT_SUCCESS(Status))
4107 {
4108 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4109 return Status;
4110 }
4111
4112 Status = ObReferenceObjectByHandle(SectionHandle,
4113 SECTION_QUERY,
4114 MmSectionObjectType,
4115 PreviousMode,
4116 (PVOID*)(PVOID)&Section,
4117 NULL);
4118 if (NT_SUCCESS(Status))
4119 {
4120 switch (SectionInformationClass)
4121 {
4122 case SectionBasicInformation:
4123 {
4124 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4125
4126 _SEH_TRY
4127 {
4128 Sbi->Attributes = Section->AllocationAttributes;
4129 if (Section->AllocationAttributes & SEC_IMAGE)
4130 {
4131 Sbi->BaseAddress = 0;
4132 Sbi->Size.QuadPart = 0;
4133 }
4134 else
4135 {
4136 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4137 Sbi->Size.QuadPart = Section->Segment->Length;
4138 }
4139
4140 if (ResultLength != NULL)
4141 {
4142 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4143 }
4144 Status = STATUS_SUCCESS;
4145 }
4146 _SEH_HANDLE
4147 {
4148 Status = _SEH_GetExceptionCode();
4149 }
4150 _SEH_END;
4151
4152 break;
4153 }
4154
4155 case SectionImageInformation:
4156 {
4157 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4158
4159 _SEH_TRY
4160 {
4161 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4162 if (Section->AllocationAttributes & SEC_IMAGE)
4163 {
4164 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4165 ImageSectionObject = Section->ImageSection;
4166
4167 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4168 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4169 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4170 Sii->SubsystemType = ImageSectionObject->Subsystem;
4171 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4172 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4173 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4174 Sii->Machine = ImageSectionObject->Machine;
4175 Sii->ImageContainsCode = ImageSectionObject->Executable;
4176 }
4177
4178 if (ResultLength != NULL)
4179 {
4180 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4181 }
4182 Status = STATUS_SUCCESS;
4183 }
4184 _SEH_HANDLE
4185 {
4186 Status = _SEH_GetExceptionCode();
4187 }
4188 _SEH_END;
4189
4190 break;
4191 }
4192 }
4193
4194 ObDereferenceObject(Section);
4195 }
4196
4197 return(Status);
4198 }
4199
4200
4201 /**
4202 * Extends size of file backed section.
4203 *
4204 * @param SectionHandle
4205 * Handle to the section object. It must be opened with
4206 * SECTION_EXTEND_SIZE access.
4207 * @param NewMaximumSize
4208 * New maximum size of the section in bytes.
4209 *
4210 * @return Status.
4211 *
4212 * @todo Move the actual code to internal function MmExtendSection.
4213 * @unimplemented
4214 */
4215 NTSTATUS STDCALL
4216 NtExtendSection(IN HANDLE SectionHandle,
4217 IN PLARGE_INTEGER NewMaximumSize)
4218 {
4219 LARGE_INTEGER SafeNewMaximumSize;
4220 PSECTION_OBJECT Section;
4221 KPROCESSOR_MODE PreviousMode;
4222 NTSTATUS Status = STATUS_SUCCESS;
4223
4224 PreviousMode = ExGetPreviousMode();
4225
4226 if(PreviousMode != KernelMode)
4227 {
4228 _SEH_TRY
4229 {
4230 /* make a copy on the stack */
4231 SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
4232 NewMaximumSize = &SafeNewMaximumSize;
4233 }
4234 _SEH_HANDLE
4235 {
4236 Status = _SEH_GetExceptionCode();
4237 }
4238 _SEH_END;
4239
4240 if(!NT_SUCCESS(Status))
4241 {
4242 return Status;
4243 }
4244 }
4245
4246 Status = ObReferenceObjectByHandle(SectionHandle,
4247 SECTION_EXTEND_SIZE,
4248 MmSectionObjectType,
4249 PreviousMode,
4250 (PVOID*)&Section,
4251 NULL);
4252 if (!NT_SUCCESS(Status))
4253 {
4254 return Status;
4255 }
4256
4257 if (!(Section->AllocationAttributes & SEC_FILE))
4258 {
4259 ObfDereferenceObject(Section);
4260 return STATUS_INVALID_PARAMETER;
4261 }
4262
4263 /*
4264 * - Acquire file extneding resource.
4265 * - Check if we're not resizing the section below it's actual size!
4266 * - Extend segments if needed.
4267 * - Set file information (FileAllocationInformation) to the new size.
4268 * - Release file extending resource.
4269 */
4270
4271 ObDereferenceObject(Section);
4272
4273 return STATUS_NOT_IMPLEMENTED;
4274 }
4275
4276
4277 /**********************************************************************
4278 * NAME INTERNAL
4279 * MmAllocateSection@4
4280 *
4281 * DESCRIPTION
4282 *
4283 * ARGUMENTS
4284 * Length
4285 *
4286 * RETURN VALUE
4287 *
4288 * NOTE
4289 * Code taken from ntoskrnl/mm/special.c.
4290 *
4291 * REVISIONS
4292 */
4293 PVOID STDCALL
4294 MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
4295 {
4296 PVOID Result;
4297 MEMORY_AREA* marea;
4298 NTSTATUS Status;
4299 ULONG i;
4300 PMADDRESS_SPACE AddressSpace;
4301 PHYSICAL_ADDRESS BoundaryAddressMultiple;
4302
4303 DPRINT("MmAllocateSection(Length %x)\n",Length);
4304
4305 BoundaryAddressMultiple.QuadPart = 0;
4306
4307 AddressSpace = MmGetKernelAddressSpace();
4308 Result = BaseAddress;
4309 MmLockAddressSpace(AddressSpace);
4310 Status = MmCreateMemoryArea (AddressSpace,
4311 MEMORY_AREA_SYSTEM,
4312 &Result,
4313 Length,
4314 0,
4315 &marea,
4316 FALSE,
4317 0,
4318 BoundaryAddressMultiple);
4319 MmUnlockAddressSpace(AddressSpace);
4320
4321 if (!NT_SUCCESS(Status))
4322 {
4323 return (NULL);
4324 }
4325 DPRINT("Result %p\n",Result);
4326 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
4327 {
4328 PFN_TYPE Page;
4329
4330 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
4331 if (!NT_SUCCESS(Status))
4332 {
4333 DbgPrint("Unable to allocate page\n");
4334 KEBUGCHECK(0);
4335 }
4336 Status = MmCreateVirtualMapping (NULL,
4337 (PVOID)((ULONG_PTR)Result + (i * PAGE_SIZE)),
4338 PAGE_READWRITE,
4339 &Page,
4340 1);
4341 if (!NT_SUCCESS(Status))
4342 {
4343 DbgPrint("Unable to create virtual mapping\n");
4344 KEBUGCHECK(0);
4345 }
4346 }
4347 return ((PVOID)Result);
4348 }
4349
4350
4351 /**********************************************************************
4352 * NAME EXPORTED
4353 * MmMapViewOfSection
4354 *
4355 * DESCRIPTION
4356 * Maps a view of a section into the virtual address space of a
4357 * process.
4358 *
4359 * ARGUMENTS
4360 * Section
4361 * Pointer to the section object.
4362 *
4363 * ProcessHandle
4364 * Pointer to the process.
4365 *
4366 * BaseAddress
4367 * Desired base address (or NULL) on entry;
4368 * Actual base address of the view on exit.
4369 *
4370 * ZeroBits
4371 * Number of high order address bits that must be zero.
4372 *
4373 * CommitSize
4374 * Size in bytes of the initially committed section of
4375 * the view.
4376 *
4377 * SectionOffset
4378 * Offset in bytes from the beginning of the section
4379 * to the beginning of the view.
4380 *
4381 * ViewSize
4382 * Desired length of map (or zero to map all) on entry
4383 * Actual length mapped on exit.
4384 *
4385 * InheritDisposition
4386 * Specified how the view is to be shared with
4387 * child processes.
4388 *
4389 * AllocationType
4390 * Type of allocation for the pages.
4391 *
4392 * Protect
4393 * Protection for the committed region of the view.
4394 *
4395 * RETURN VALUE
4396 * Status.
4397 *
4398 * @implemented
4399 */
4400 NTSTATUS STDCALL
4401 MmMapViewOfSection(IN PVOID SectionObject,
4402 IN PEPROCESS Process,
4403 IN OUT PVOID *BaseAddress,
4404 IN ULONG ZeroBits,
4405 IN ULONG CommitSize,
4406 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4407 IN OUT PULONG ViewSize,
4408 IN SECTION_INHERIT InheritDisposition,
4409 IN ULONG AllocationType,
4410 IN ULONG Protect)
4411 {
4412 PSECTION_OBJECT Section;
4413 PMADDRESS_SPACE AddressSpace;
4414 ULONG ViewOffset;
4415 NTSTATUS Status = STATUS_SUCCESS;
4416
4417 ASSERT(Process);
4418
4419 if (Protect != PAGE_READONLY &&
4420 Protect != PAGE_READWRITE &&
4421 Protect != PAGE_WRITECOPY &&
4422 Protect != PAGE_EXECUTE &&
4423 Protect != PAGE_EXECUTE_READ &&
4424 Protect != PAGE_EXECUTE_READWRITE &&
4425 Protect != PAGE_EXECUTE_WRITECOPY)
4426 {
4427 CHECKPOINT1;
4428 return STATUS_INVALID_PAGE_PROTECTION;
4429 }
4430
4431
4432 Section = (PSECTION_OBJECT)SectionObject;
4433 AddressSpace = &Process->AddressSpace;
4434
4435 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4436
4437 MmLockAddressSpace(AddressSpace);
4438
4439 if (Section->AllocationAttributes & SEC_IMAGE)
4440 {
4441 ULONG i;
4442 ULONG NrSegments;
4443 ULONG_PTR ImageBase;
4444 ULONG ImageSize;
4445 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4446 PMM_SECTION_SEGMENT SectionSegments;
4447
4448 ImageSectionObject = Section->ImageSection;
4449 SectionSegments = ImageSectionObject->Segments;
4450 NrSegments = ImageSectionObject->NrSegments;
4451
4452
4453 ImageBase = (ULONG_PTR)*BaseAddress;
4454 if (ImageBase == 0)
4455 {
4456 ImageBase = ImageSectionObject->ImageBase;
4457 }
4458
4459 ImageSize = 0;
4460 for (i = 0; i < NrSegments; i++)
4461 {
4462 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4463 {
4464 ULONG_PTR MaxExtent;
4465 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4466 SectionSegments[i].Length;
4467 ImageSize = max(ImageSize, MaxExtent);
4468 }
4469 }
4470
4471 /* Check there is enough space to map the section at that point. */
4472 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4473 PAGE_ROUND_UP(ImageSize)) != NULL)
4474 {
4475 /* Fail if the user requested a fixed base address. */
4476 if ((*BaseAddress) != NULL)
4477 {
4478 MmUnlockAddressSpace(AddressSpace);
4479 return(STATUS_UNSUCCESSFUL);
4480 }
4481 /* Otherwise find a gap to map the image. */
4482 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4483 if (ImageBase == 0)
4484 {
4485 MmUnlockAddressSpace(AddressSpace);
4486 return(STATUS_UNSUCCESSFUL);
4487 }
4488 }
4489
4490 for (i = 0; i < NrSegments; i++)
4491 {
4492 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4493 {
4494 PVOID SBaseAddress = (PVOID)
4495 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4496 MmLockSectionSegment(&SectionSegments[i]);
4497 Status = MmMapViewOfSegment(AddressSpace,
4498 Section,
4499 &SectionSegments[i],
4500 &SBaseAddress,
4501 SectionSegments[i].Length,
4502 SectionSegments[i].Protection,
4503 0,
4504 0);
4505 MmUnlockSectionSegment(&SectionSegments[i]);
4506 if (!NT_SUCCESS(Status))
4507 {
4508 MmUnlockAddressSpace(AddressSpace);
4509 return(Status);
4510 }
4511 }
4512 }
4513
4514 *BaseAddress = (PVOID)ImageBase;
4515 }
4516 else
4517 {
4518 /* check for write access */
4519 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4520 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4521 {
4522 CHECKPOINT1;
4523 return STATUS_SECTION_PROTECTION;
4524 }
4525 /* check for read access */
4526 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4527 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4528 {
4529 CHECKPOINT1;
4530 return STATUS_SECTION_PROTECTION;
4531 }
4532 /* check for execute access */
4533 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4534 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4535 {
4536 CHECKPOINT1;
4537 return STATUS_SECTION_PROTECTION;
4538 }
4539
4540 if (ViewSize == NULL)
4541 {
4542 /* Following this pointer would lead to us to the dark side */
4543 /* What to do? Bugcheck? Return status? Do the mambo? */
4544 KEBUGCHECK(MEMORY_MANAGEMENT);
4545 }
4546
4547 if (SectionOffset == NULL)
4548 {
4549 ViewOffset = 0;
4550 }
4551 else
4552 {
4553 ViewOffset = SectionOffset->u.LowPart;
4554 }
4555
4556 if ((ViewOffset % PAGE_SIZE) != 0)
4557 {
4558 MmUnlockAddressSpace(AddressSpace);
4559 return(STATUS_MAPPED_ALIGNMENT);
4560 }
4561
4562 if ((*ViewSize) == 0)
4563 {
4564 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4565 }
4566 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4567 {
4568 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4569 }
4570
4571 MmLockSectionSegment(Section->Segment);
4572 Status = MmMapViewOfSegment(AddressSpace,
4573 Section,
4574 Section->Segment,
4575 BaseAddress,
4576 *ViewSize,
4577 Protect,
4578 ViewOffset,
4579 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4580 MmUnlockSectionSegment(Section->Segment);
4581 if (!NT_SUCCESS(Status))
4582 {
4583 MmUnlockAddressSpace(AddressSpace);
4584 return(Status);
4585 }
4586 }
4587
4588 MmUnlockAddressSpace(AddressSpace);
4589
4590 return(STATUS_SUCCESS);
4591 }
4592
4593 /*
4594 * @unimplemented
4595 */
4596 BOOLEAN STDCALL
4597 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4598 IN PLARGE_INTEGER NewFileSize)
4599 {
4600 UNIMPLEMENTED;
4601 return (FALSE);
4602 }
4603
4604
4605 /*
4606 * @unimplemented
4607 */
4608 BOOLEAN STDCALL
4609 MmDisableModifiedWriteOfSection (DWORD Unknown0)
4610 {
4611 UNIMPLEMENTED;
4612 return (FALSE);
4613 }
4614
4615 /*
4616 * @implemented
4617 */
4618 BOOLEAN STDCALL
4619 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4620 IN MMFLUSH_TYPE FlushType)
4621 {
4622 switch(FlushType)
4623 {
4624 case MmFlushForDelete:
4625 if (SectionObjectPointer->ImageSectionObject ||
4626 SectionObjectPointer->DataSectionObject)
4627 {
4628 return FALSE;
4629 }
4630 CcRosSetRemoveOnClose(SectionObjectPointer);
4631 return TRUE;
4632 case MmFlushForWrite:
4633 break;
4634 }
4635 return FALSE;
4636 }
4637
4638 /*
4639 * @unimplemented
4640 */
4641 BOOLEAN STDCALL
4642 MmForceSectionClosed (
4643 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4644 IN BOOLEAN DelayClose)
4645 {
4646 UNIMPLEMENTED;
4647 return (FALSE);
4648 }
4649
4650
4651 /*
4652 * @implemented
4653 */
4654 NTSTATUS STDCALL
4655 MmMapViewInSystemSpace (IN PVOID SectionObject,
4656 OUT PVOID * MappedBase,
4657 IN OUT PULONG ViewSize)
4658 {
4659 PSECTION_OBJECT Section;
4660 PMADDRESS_SPACE AddressSpace;
4661 NTSTATUS Status;
4662
4663 DPRINT("MmMapViewInSystemSpace() called\n");
4664
4665 Section = (PSECTION_OBJECT)SectionObject;
4666 AddressSpace = MmGetKernelAddressSpace();
4667
4668 MmLockAddressSpace(AddressSpace);
4669
4670
4671 if ((*ViewSize) == 0)
4672 {
4673 (*ViewSize) = Section->MaximumSize.u.LowPart;
4674 }
4675 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4676 {
4677 (*ViewSize) = Section->MaximumSize.u.LowPart;
4678 }
4679
4680 MmLockSectionSegment(Section->Segment);
4681
4682
4683 Status = MmMapViewOfSegment(AddressSpace,
4684 Section,
4685 Section->Segment,
4686 MappedBase,
4687 *ViewSize,
4688 PAGE_READWRITE,
4689 0,
4690 0);
4691
4692 MmUnlockSectionSegment(Section->Segment);
4693 MmUnlockAddressSpace(AddressSpace);
4694
4695 return Status;
4696 }
4697
4698 /*
4699 * @unimplemented
4700 */
4701 NTSTATUS
4702 STDCALL
4703 MmMapViewInSessionSpace (
4704 IN PVOID Section,
4705 OUT PVOID *MappedBase,
4706 IN OUT PSIZE_T ViewSize
4707 )
4708 {
4709 UNIMPLEMENTED;
4710 return STATUS_NOT_IMPLEMENTED;
4711 }
4712
4713
4714 /*
4715 * @implemented
4716 */
4717 NTSTATUS STDCALL
4718 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4719 {
4720 PMADDRESS_SPACE AddressSpace;
4721 NTSTATUS Status;
4722
4723 DPRINT("MmUnmapViewInSystemSpace() called\n");
4724
4725 AddressSpace = MmGetKernelAddressSpace();
4726
4727 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4728
4729 return Status;
4730 }
4731
4732 /*
4733 * @unimplemented
4734 */
4735 NTSTATUS
4736 STDCALL
4737 MmUnmapViewInSessionSpace (
4738 IN PVOID MappedBase
4739 )
4740 {
4741 UNIMPLEMENTED;
4742 return STATUS_NOT_IMPLEMENTED;
4743 }
4744
4745 /*
4746 * @unimplemented
4747 */
4748 NTSTATUS STDCALL
4749 MmSetBankedSection (DWORD Unknown0,
4750 DWORD Unknown1,
4751 DWORD Unknown2,
4752 DWORD Unknown3,
4753 DWORD Unknown4,
4754 DWORD Unknown5)
4755 {
4756 UNIMPLEMENTED;
4757 return (STATUS_NOT_IMPLEMENTED);
4758 }
4759
4760
4761 /**********************************************************************
4762 * NAME EXPORTED
4763 * MmCreateSection@
4764 *
4765 * DESCRIPTION
4766 * Creates a section object.
4767 *
4768 * ARGUMENTS
4769 * SectionObject (OUT)
4770 * Caller supplied storage for the resulting pointer
4771 * to a SECTION_OBJECT instance;
4772 *
4773 * DesiredAccess
4774 * Specifies the desired access to the section can be a
4775 * combination of:
4776 * STANDARD_RIGHTS_REQUIRED |
4777 * SECTION_QUERY |
4778 * SECTION_MAP_WRITE |
4779 * SECTION_MAP_READ |
4780 * SECTION_MAP_EXECUTE
4781 *
4782 * ObjectAttributes [OPTIONAL]
4783 * Initialized attributes for the object can be used
4784 * to create a named section;
4785 *
4786 * MaximumSize
4787 * Maximizes the size of the memory section. Must be
4788 * non-NULL for a page-file backed section.
4789 * If value specified for a mapped file and the file is
4790 * not large enough, file will be extended.
4791 *
4792 * SectionPageProtection
4793 * Can be a combination of:
4794 * PAGE_READONLY |
4795 * PAGE_READWRITE |
4796 * PAGE_WRITEONLY |
4797 * PAGE_WRITECOPY
4798 *
4799 * AllocationAttributes
4800 * Can be a combination of:
4801 * SEC_IMAGE |
4802 * SEC_RESERVE
4803 *
4804 * FileHandle
4805 * Handle to a file to create a section mapped to a file
4806 * instead of a memory backed section;
4807 *
4808 * File
4809 * Unknown.
4810 *
4811 * RETURN VALUE
4812 * Status.
4813 *
4814 * @implemented
4815 */
4816 NTSTATUS STDCALL
4817 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
4818 IN ACCESS_MASK DesiredAccess,
4819 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4820 IN PLARGE_INTEGER MaximumSize,
4821 IN ULONG SectionPageProtection,
4822 IN ULONG AllocationAttributes,
4823 IN HANDLE FileHandle OPTIONAL,
4824 IN PFILE_OBJECT File OPTIONAL)
4825 {
4826 ULONG Protection;
4827
4828 /*
4829 * Check the protection
4830 */
4831 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
4832 if (Protection != PAGE_NOACCESS &&
4833 Protection != PAGE_READONLY &&
4834 Protection != PAGE_READWRITE &&
4835 Protection != PAGE_WRITECOPY &&
4836 Protection != PAGE_EXECUTE &&
4837 Protection != PAGE_EXECUTE_READ &&
4838 Protection != PAGE_EXECUTE_READWRITE &&
4839 Protection != PAGE_EXECUTE_WRITECOPY)
4840 {
4841 CHECKPOINT1;
4842 return STATUS_INVALID_PAGE_PROTECTION;
4843 }
4844
4845 if (AllocationAttributes & SEC_IMAGE)
4846 {
4847 return(MmCreateImageSection(SectionObject,
4848 DesiredAccess,
4849 ObjectAttributes,
4850 MaximumSize,
4851 SectionPageProtection,
4852 AllocationAttributes,
4853 FileHandle));
4854 }
4855
4856 if (FileHandle != NULL)
4857 {
4858 return(MmCreateDataFileSection(SectionObject,
4859 DesiredAccess,
4860 ObjectAttributes,
4861 MaximumSize,
4862 SectionPageProtection,
4863 AllocationAttributes,
4864 FileHandle));
4865 }
4866
4867 return(MmCreatePageFileSection(SectionObject,
4868 DesiredAccess,
4869 ObjectAttributes,
4870 MaximumSize,
4871 SectionPageProtection,
4872 AllocationAttributes));
4873 }
4874
4875 /* EOF */