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