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