- Remove the (now deprecated) ntoskrnl/internal/debug.h header and fix all its includ...
[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 <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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
373 }
374 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
375 {
376 DPRINT1("Maximum share count reached\n");
377 ASSERT(FALSE);
378 }
379 if (IS_SWAP_FROM_SSE(Entry))
380 {
381 ASSERT(FALSE);
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 ASSERT(FALSE);
403 }
404 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
405 {
406 DPRINT1("Zero share count for unshare\n");
407 ASSERT(FALSE);
408 }
409 if (IS_SWAP_FROM_SSE(Entry))
410 {
411 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
797 }
798 if (PageOp->Status == STATUS_PENDING)
799 {
800 DPRINT1("Woke for page op before completion\n");
801 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
899 }
900
901 Status = MmReadFromSwapPage(SwapEntry, Page);
902 if (!NT_SUCCESS(Status))
903 {
904 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
905 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
1137 }
1138
1139 Status = MmReadFromSwapPage(SwapEntry, Page);
1140 if (!NT_SUCCESS(Status))
1141 {
1142 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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_ACCESS_VIOLATION);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
1325 }
1326 if (PageOp->Status == STATUS_PENDING)
1327 {
1328 DPRINT1("Woke for page op before completion\n");
1329 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
1377 return(Status);
1378 }
1379 if (!NT_SUCCESS(Status))
1380 {
1381 DPRINT1("Unable to create virtual mapping\n");
1382 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
1628 }
1629 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1630 if (!NT_SUCCESS(Status))
1631 {
1632 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1633 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 ASSERT(FALSE);
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 return STATUS_INVALID_PAGE_PROTECTION;
2040 }
2041
2042 *OldProtect = Region->Protect;
2043 Status = MmAlterRegion(AddressSpace, MemoryArea->StartingAddress,
2044 &MemoryArea->Data.SectionData.RegionListHead,
2045 BaseAddress, Length, Region->Type, Protect,
2046 MmAlterViewAttributes);
2047
2048 return(Status);
2049 }
2050
2051 NTSTATUS STDCALL
2052 MmQuerySectionView(PMEMORY_AREA MemoryArea,
2053 PVOID Address,
2054 PMEMORY_BASIC_INFORMATION Info,
2055 PULONG ResultLength)
2056 {
2057 PMM_REGION Region;
2058 PVOID RegionBaseAddress;
2059 PROS_SECTION_OBJECT Section;
2060 PMM_SECTION_SEGMENT Segment;
2061
2062 Region = MmFindRegion((PVOID)MemoryArea->StartingAddress,
2063 &MemoryArea->Data.SectionData.RegionListHead,
2064 Address, &RegionBaseAddress);
2065 if (Region == NULL)
2066 {
2067 return STATUS_UNSUCCESSFUL;
2068 }
2069
2070 Section = MemoryArea->Data.SectionData.Section;
2071 if (Section->AllocationAttributes & SEC_IMAGE)
2072 {
2073 Segment = MemoryArea->Data.SectionData.Segment;
2074 Info->AllocationBase = (PUCHAR)MemoryArea->StartingAddress - Segment->VirtualAddress;
2075 Info->Type = MEM_IMAGE;
2076 }
2077 else
2078 {
2079 Info->AllocationBase = MemoryArea->StartingAddress;
2080 Info->Type = MEM_MAPPED;
2081 }
2082 Info->BaseAddress = RegionBaseAddress;
2083 Info->AllocationProtect = MemoryArea->Protect;
2084 Info->RegionSize = Region->Length;
2085 Info->State = MEM_COMMIT;
2086 Info->Protect = Region->Protect;
2087
2088 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
2089 return(STATUS_SUCCESS);
2090 }
2091
2092 VOID
2093 NTAPI
2094 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
2095 {
2096 ULONG Length;
2097 ULONG Offset;
2098 ULONG Entry;
2099 ULONG SavedSwapEntry;
2100 PFN_TYPE Page;
2101
2102 Page = 0;
2103
2104 Length = PAGE_ROUND_UP(Segment->Length);
2105 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2106 {
2107 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2108 if (Entry)
2109 {
2110 if (IS_SWAP_FROM_SSE(Entry))
2111 {
2112 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2113 }
2114 else
2115 {
2116 Page = PFN_FROM_SSE(Entry);
2117 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
2118 if (SavedSwapEntry != 0)
2119 {
2120 MmSetSavedSwapEntryPage(Page, 0);
2121 MmFreeSwapPage(SavedSwapEntry);
2122 }
2123 MmReleasePageMemoryConsumer(MC_USER, Page);
2124 }
2125 MmSetPageEntrySectionSegment(Segment, Offset, 0);
2126 }
2127 }
2128 }
2129
2130 VOID STDCALL
2131 MmpDeleteSection(PVOID ObjectBody)
2132 {
2133 PROS_SECTION_OBJECT Section = (PROS_SECTION_OBJECT)ObjectBody;
2134
2135 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2136 if (Section->AllocationAttributes & SEC_IMAGE)
2137 {
2138 ULONG i;
2139 ULONG NrSegments;
2140 ULONG RefCount;
2141 PMM_SECTION_SEGMENT SectionSegments;
2142
2143 /*
2144 * NOTE: Section->ImageSection can be NULL for short time
2145 * during the section creating. If we fail for some reason
2146 * until the image section is properly initialized we shouldn't
2147 * process further here.
2148 */
2149 if (Section->ImageSection == NULL)
2150 return;
2151
2152 SectionSegments = Section->ImageSection->Segments;
2153 NrSegments = Section->ImageSection->NrSegments;
2154
2155 for (i = 0; i < NrSegments; i++)
2156 {
2157 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2158 {
2159 MmLockSectionSegment(&SectionSegments[i]);
2160 }
2161 RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount);
2162 if (SectionSegments[i].Characteristics & IMAGE_SCN_MEM_SHARED)
2163 {
2164 if (RefCount == 0)
2165 {
2166 MmpFreePageFileSegment(&SectionSegments[i]);
2167 }
2168 MmUnlockSectionSegment(&SectionSegments[i]);
2169 }
2170 }
2171 }
2172 else
2173 {
2174 /*
2175 * NOTE: Section->Segment can be NULL for short time
2176 * during the section creating.
2177 */
2178 if (Section->Segment == NULL)
2179 return;
2180
2181 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2182 {
2183 MmpFreePageFileSegment(Section->Segment);
2184 MmFreePageTablesSectionSegment(Section->Segment);
2185 ExFreePool(Section->Segment);
2186 Section->Segment = NULL;
2187 }
2188 else
2189 {
2190 (void)InterlockedDecrementUL(&Section->Segment->ReferenceCount);
2191 }
2192 }
2193 if (Section->FileObject != NULL)
2194 {
2195 CcRosDereferenceCache(Section->FileObject);
2196 ObDereferenceObject(Section->FileObject);
2197 Section->FileObject = NULL;
2198 }
2199 }
2200
2201 VOID STDCALL
2202 MmpCloseSection(IN PEPROCESS Process OPTIONAL,
2203 IN PVOID Object,
2204 IN ACCESS_MASK GrantedAccess,
2205 IN ULONG ProcessHandleCount,
2206 IN ULONG SystemHandleCount)
2207 {
2208 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2209 Object, ProcessHandleCount);
2210 }
2211
2212 NTSTATUS
2213 INIT_FUNCTION
2214 NTAPI
2215 MmCreatePhysicalMemorySection(VOID)
2216 {
2217 PROS_SECTION_OBJECT PhysSection;
2218 NTSTATUS Status;
2219 OBJECT_ATTRIBUTES Obj;
2220 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
2221 LARGE_INTEGER SectionSize;
2222 HANDLE Handle;
2223
2224 /*
2225 * Create the section mapping physical memory
2226 */
2227 SectionSize.QuadPart = 0xFFFFFFFF;
2228 InitializeObjectAttributes(&Obj,
2229 &Name,
2230 OBJ_PERMANENT,
2231 NULL,
2232 NULL);
2233 Status = MmCreateSection((PVOID)&PhysSection,
2234 SECTION_ALL_ACCESS,
2235 &Obj,
2236 &SectionSize,
2237 PAGE_EXECUTE_READWRITE,
2238 0,
2239 NULL,
2240 NULL);
2241 if (!NT_SUCCESS(Status))
2242 {
2243 DPRINT1("Failed to create PhysicalMemory section\n");
2244 ASSERT(FALSE);
2245 }
2246 Status = ObInsertObject(PhysSection,
2247 NULL,
2248 SECTION_ALL_ACCESS,
2249 0,
2250 NULL,
2251 &Handle);
2252 if (!NT_SUCCESS(Status))
2253 {
2254 ObDereferenceObject(PhysSection);
2255 }
2256 ObCloseHandle(Handle, KernelMode);
2257 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2258 PhysSection->Segment->Flags &= ~MM_PAGEFILE_SEGMENT;
2259
2260 return(STATUS_SUCCESS);
2261 }
2262
2263 NTSTATUS
2264 INIT_FUNCTION
2265 NTAPI
2266 MmInitSectionImplementation(VOID)
2267 {
2268 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
2269 UNICODE_STRING Name;
2270
2271 DPRINT("Creating Section Object Type\n");
2272
2273 /* Initialize the Section object type */
2274 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
2275 RtlInitUnicodeString(&Name, L"Section");
2276 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
2277 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(ROS_SECTION_OBJECT);
2278 ObjectTypeInitializer.PoolType = PagedPool;
2279 ObjectTypeInitializer.UseDefaultObject = TRUE;
2280 ObjectTypeInitializer.GenericMapping = MmpSectionMapping;
2281 ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection;
2282 ObjectTypeInitializer.CloseProcedure = MmpCloseSection;
2283 ObjectTypeInitializer.ValidAccessMask = SECTION_ALL_ACCESS;
2284 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &MmSectionObjectType);
2285
2286 return(STATUS_SUCCESS);
2287 }
2288
2289 NTSTATUS
2290 NTAPI
2291 MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
2292 ACCESS_MASK DesiredAccess,
2293 POBJECT_ATTRIBUTES ObjectAttributes,
2294 PLARGE_INTEGER UMaximumSize,
2295 ULONG SectionPageProtection,
2296 ULONG AllocationAttributes)
2297 /*
2298 * Create a section which is backed by the pagefile
2299 */
2300 {
2301 LARGE_INTEGER MaximumSize;
2302 PROS_SECTION_OBJECT Section;
2303 PMM_SECTION_SEGMENT Segment;
2304 NTSTATUS Status;
2305
2306 if (UMaximumSize == NULL)
2307 {
2308 return(STATUS_UNSUCCESSFUL);
2309 }
2310 MaximumSize = *UMaximumSize;
2311
2312 /*
2313 * Create the section
2314 */
2315 Status = ObCreateObject(ExGetPreviousMode(),
2316 MmSectionObjectType,
2317 ObjectAttributes,
2318 ExGetPreviousMode(),
2319 NULL,
2320 sizeof(ROS_SECTION_OBJECT),
2321 0,
2322 0,
2323 (PVOID*)(PVOID)&Section);
2324 if (!NT_SUCCESS(Status))
2325 {
2326 return(Status);
2327 }
2328
2329 /*
2330 * Initialize it
2331 */
2332 Section->SectionPageProtection = SectionPageProtection;
2333 Section->AllocationAttributes = AllocationAttributes;
2334 Section->Segment = NULL;
2335 Section->FileObject = NULL;
2336 Section->MaximumSize = MaximumSize;
2337 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2338 TAG_MM_SECTION_SEGMENT);
2339 if (Segment == NULL)
2340 {
2341 ObDereferenceObject(Section);
2342 return(STATUS_NO_MEMORY);
2343 }
2344 Section->Segment = Segment;
2345 Segment->ReferenceCount = 1;
2346 ExInitializeFastMutex(&Segment->Lock);
2347 Segment->FileOffset = 0;
2348 Segment->Protection = SectionPageProtection;
2349 Segment->RawLength = MaximumSize.u.LowPart;
2350 Segment->Length = PAGE_ROUND_UP(MaximumSize.u.LowPart);
2351 Segment->Flags = MM_PAGEFILE_SEGMENT;
2352 Segment->WriteCopy = FALSE;
2353 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2354 Segment->VirtualAddress = 0;
2355 Segment->Characteristics = 0;
2356 *SectionObject = Section;
2357 return(STATUS_SUCCESS);
2358 }
2359
2360
2361 NTSTATUS
2362 NTAPI
2363 MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
2364 ACCESS_MASK DesiredAccess,
2365 POBJECT_ATTRIBUTES ObjectAttributes,
2366 PLARGE_INTEGER UMaximumSize,
2367 ULONG SectionPageProtection,
2368 ULONG AllocationAttributes,
2369 HANDLE FileHandle)
2370 /*
2371 * Create a section backed by a data file
2372 */
2373 {
2374 PROS_SECTION_OBJECT Section;
2375 NTSTATUS Status;
2376 LARGE_INTEGER MaximumSize;
2377 PFILE_OBJECT FileObject;
2378 PMM_SECTION_SEGMENT Segment;
2379 ULONG FileAccess;
2380 IO_STATUS_BLOCK Iosb;
2381 LARGE_INTEGER Offset;
2382 CHAR Buffer;
2383 FILE_STANDARD_INFORMATION FileInfo;
2384
2385 /*
2386 * Create the section
2387 */
2388 Status = ObCreateObject(ExGetPreviousMode(),
2389 MmSectionObjectType,
2390 ObjectAttributes,
2391 ExGetPreviousMode(),
2392 NULL,
2393 sizeof(ROS_SECTION_OBJECT),
2394 0,
2395 0,
2396 (PVOID*)(PVOID)&Section);
2397 if (!NT_SUCCESS(Status))
2398 {
2399 return(Status);
2400 }
2401 /*
2402 * Initialize it
2403 */
2404 Section->SectionPageProtection = SectionPageProtection;
2405 Section->AllocationAttributes = AllocationAttributes;
2406 Section->Segment = NULL;
2407
2408 /*
2409 * Check file access required
2410 */
2411 if (SectionPageProtection & PAGE_READWRITE ||
2412 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2413 {
2414 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2415 }
2416 else
2417 {
2418 FileAccess = FILE_READ_DATA;
2419 }
2420
2421 /*
2422 * Reference the file handle
2423 */
2424 Status = ObReferenceObjectByHandle(FileHandle,
2425 FileAccess,
2426 IoFileObjectType,
2427 ExGetPreviousMode(),
2428 (PVOID*)(PVOID)&FileObject,
2429 NULL);
2430 if (!NT_SUCCESS(Status))
2431 {
2432 ObDereferenceObject(Section);
2433 return(Status);
2434 }
2435
2436 /*
2437 * FIXME: This is propably not entirely correct. We can't look into
2438 * the standard FCB header because it might not be initialized yet
2439 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2440 * standard file information is filled on first request).
2441 */
2442 Status = IoQueryFileInformation(FileObject,
2443 FileStandardInformation,
2444 sizeof(FILE_STANDARD_INFORMATION),
2445 &FileInfo,
2446 &Iosb.Information);
2447 if (!NT_SUCCESS(Status))
2448 {
2449 ObDereferenceObject(Section);
2450 ObDereferenceObject(FileObject);
2451 return Status;
2452 }
2453
2454 /*
2455 * FIXME: Revise this once a locking order for file size changes is
2456 * decided
2457 */
2458 if (UMaximumSize != NULL)
2459 {
2460 MaximumSize = *UMaximumSize;
2461 }
2462 else
2463 {
2464 MaximumSize = FileInfo.EndOfFile;
2465 /* Mapping zero-sized files isn't allowed. */
2466 if (MaximumSize.QuadPart == 0)
2467 {
2468 ObDereferenceObject(Section);
2469 ObDereferenceObject(FileObject);
2470 return STATUS_FILE_INVALID;
2471 }
2472 }
2473
2474 if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart)
2475 {
2476 Status = IoSetInformation(FileObject,
2477 FileAllocationInformation,
2478 sizeof(LARGE_INTEGER),
2479 &MaximumSize);
2480 if (!NT_SUCCESS(Status))
2481 {
2482 ObDereferenceObject(Section);
2483 ObDereferenceObject(FileObject);
2484 return(STATUS_SECTION_NOT_EXTENDED);
2485 }
2486 }
2487
2488 if (FileObject->SectionObjectPointer == NULL ||
2489 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2490 {
2491 /*
2492 * Read a bit so caching is initiated for the file object.
2493 * This is only needed because MiReadPage currently cannot
2494 * handle non-cached streams.
2495 */
2496 Offset.QuadPart = 0;
2497 Status = ZwReadFile(FileHandle,
2498 NULL,
2499 NULL,
2500 NULL,
2501 &Iosb,
2502 &Buffer,
2503 sizeof (Buffer),
2504 &Offset,
2505 0);
2506 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2507 {
2508 ObDereferenceObject(Section);
2509 ObDereferenceObject(FileObject);
2510 return(Status);
2511 }
2512 if (FileObject->SectionObjectPointer == NULL ||
2513 FileObject->SectionObjectPointer->SharedCacheMap == NULL)
2514 {
2515 /* FIXME: handle this situation */
2516 ObDereferenceObject(Section);
2517 ObDereferenceObject(FileObject);
2518 return STATUS_INVALID_PARAMETER;
2519 }
2520 }
2521
2522 /*
2523 * Lock the file
2524 */
2525 Status = MmspWaitForFileLock(FileObject);
2526 if (Status != STATUS_SUCCESS)
2527 {
2528 ObDereferenceObject(Section);
2529 ObDereferenceObject(FileObject);
2530 return(Status);
2531 }
2532
2533 /*
2534 * If this file hasn't been mapped as a data file before then allocate a
2535 * section segment to describe the data file mapping
2536 */
2537 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2538 {
2539 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2540 TAG_MM_SECTION_SEGMENT);
2541 if (Segment == NULL)
2542 {
2543 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2544 ObDereferenceObject(Section);
2545 ObDereferenceObject(FileObject);
2546 return(STATUS_NO_MEMORY);
2547 }
2548 Section->Segment = Segment;
2549 Segment->ReferenceCount = 1;
2550 ExInitializeFastMutex(&Segment->Lock);
2551 /*
2552 * Set the lock before assigning the segment to the file object
2553 */
2554 ExAcquireFastMutex(&Segment->Lock);
2555 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2556
2557 Segment->FileOffset = 0;
2558 Segment->Protection = SectionPageProtection;
2559 Segment->Flags = MM_DATAFILE_SEGMENT;
2560 Segment->Characteristics = 0;
2561 Segment->WriteCopy = FALSE;
2562 if (AllocationAttributes & SEC_RESERVE)
2563 {
2564 Segment->Length = Segment->RawLength = 0;
2565 }
2566 else
2567 {
2568 Segment->RawLength = MaximumSize.u.LowPart;
2569 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2570 }
2571 Segment->VirtualAddress = 0;
2572 RtlZeroMemory(&Segment->PageDirectory, sizeof(SECTION_PAGE_DIRECTORY));
2573 }
2574 else
2575 {
2576 /*
2577 * If the file is already mapped as a data file then we may need
2578 * to extend it
2579 */
2580 Segment =
2581 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2582 DataSectionObject;
2583 Section->Segment = Segment;
2584 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
2585 MmLockSectionSegment(Segment);
2586
2587 if (MaximumSize.u.LowPart > Segment->RawLength &&
2588 !(AllocationAttributes & SEC_RESERVE))
2589 {
2590 Segment->RawLength = MaximumSize.u.LowPart;
2591 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2592 }
2593 }
2594 MmUnlockSectionSegment(Segment);
2595 Section->FileObject = FileObject;
2596 Section->MaximumSize = MaximumSize;
2597 CcRosReferenceCache(FileObject);
2598 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2599 *SectionObject = Section;
2600 return(STATUS_SUCCESS);
2601 }
2602
2603 /*
2604 TODO: not that great (declaring loaders statically, having to declare all of
2605 them, having to keep them extern, etc.), will fix in the future
2606 */
2607 extern NTSTATUS NTAPI PeFmtCreateSection
2608 (
2609 IN CONST VOID * FileHeader,
2610 IN SIZE_T FileHeaderSize,
2611 IN PVOID File,
2612 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2613 OUT PULONG Flags,
2614 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2615 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2616 );
2617
2618 extern NTSTATUS NTAPI ElfFmtCreateSection
2619 (
2620 IN CONST VOID * FileHeader,
2621 IN SIZE_T FileHeaderSize,
2622 IN PVOID File,
2623 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2624 OUT PULONG Flags,
2625 IN PEXEFMT_CB_READ_FILE ReadFileCb,
2626 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2627 );
2628
2629 /* TODO: this is a standard DDK/PSDK macro */
2630 #ifndef RTL_NUMBER_OF
2631 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2632 #endif
2633
2634 static PEXEFMT_LOADER ExeFmtpLoaders[] =
2635 {
2636 PeFmtCreateSection,
2637 #ifdef __ELF
2638 ElfFmtCreateSection
2639 #endif
2640 };
2641
2642 static
2643 PMM_SECTION_SEGMENT
2644 NTAPI
2645 ExeFmtpAllocateSegments(IN ULONG NrSegments)
2646 {
2647 SIZE_T SizeOfSegments;
2648 PMM_SECTION_SEGMENT Segments;
2649
2650 /* TODO: check for integer overflow */
2651 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments;
2652
2653 Segments = ExAllocatePoolWithTag(NonPagedPool,
2654 SizeOfSegments,
2655 TAG_MM_SECTION_SEGMENT);
2656
2657 if(Segments)
2658 RtlZeroMemory(Segments, SizeOfSegments);
2659
2660 return Segments;
2661 }
2662
2663 static
2664 NTSTATUS
2665 NTAPI
2666 ExeFmtpReadFile(IN PVOID File,
2667 IN PLARGE_INTEGER Offset,
2668 IN ULONG Length,
2669 OUT PVOID * Data,
2670 OUT PVOID * AllocBase,
2671 OUT PULONG ReadSize)
2672 {
2673 NTSTATUS Status;
2674 LARGE_INTEGER FileOffset;
2675 ULONG AdjustOffset;
2676 ULONG OffsetAdjustment;
2677 ULONG BufferSize;
2678 ULONG UsedSize;
2679 PVOID Buffer;
2680
2681 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
2682
2683 if(Length == 0)
2684 {
2685 ASSERT(FALSE);
2686 }
2687
2688 FileOffset = *Offset;
2689
2690 /* Negative/special offset: it cannot be used in this context */
2691 if(FileOffset.u.HighPart < 0)
2692 {
2693 ASSERT(FALSE);
2694 }
2695
2696 AdjustOffset = PAGE_ROUND_DOWN(FileOffset.u.LowPart);
2697 OffsetAdjustment = FileOffset.u.LowPart - AdjustOffset;
2698 FileOffset.u.LowPart = AdjustOffset;
2699
2700 BufferSize = Length + OffsetAdjustment;
2701 BufferSize = PAGE_ROUND_UP(BufferSize);
2702
2703 /*
2704 * It's ok to use paged pool, because this is a temporary buffer only used in
2705 * the loading of executables. The assumption is that MmCreateSection is
2706 * always called at low IRQLs and that these buffers don't survive a brief
2707 * initialization phase
2708 */
2709 Buffer = ExAllocatePoolWithTag(PagedPool,
2710 BufferSize,
2711 TAG('M', 'm', 'X', 'r'));
2712
2713 UsedSize = 0;
2714
2715 #if 0
2716 Status = MmspPageRead(File,
2717 Buffer,
2718 BufferSize,
2719 &FileOffset,
2720 &UsedSize);
2721 #else
2722 /*
2723 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2724 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2725 * to initialize internal state is even worse. Our cache manager is in need of
2726 * professional help
2727 */
2728 {
2729 IO_STATUS_BLOCK Iosb;
2730
2731 Status = ZwReadFile(File,
2732 NULL,
2733 NULL,
2734 NULL,
2735 &Iosb,
2736 Buffer,
2737 BufferSize,
2738 &FileOffset,
2739 NULL);
2740
2741 if(NT_SUCCESS(Status))
2742 {
2743 UsedSize = Iosb.Information;
2744 }
2745 }
2746 #endif
2747
2748 if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
2749 {
2750 Status = STATUS_IN_PAGE_ERROR;
2751 ASSERT(!NT_SUCCESS(Status));
2752 }
2753
2754 if(NT_SUCCESS(Status))
2755 {
2756 *Data = (PVOID)((ULONG_PTR)Buffer + OffsetAdjustment);
2757 *AllocBase = Buffer;
2758 *ReadSize = UsedSize - OffsetAdjustment;
2759 }
2760 else
2761 {
2762 ExFreePool(Buffer);
2763 }
2764
2765 return Status;
2766 }
2767
2768 #ifdef NASSERT
2769 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2770 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2771 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2772 #else
2773 static
2774 VOID
2775 NTAPI
2776 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2777 {
2778 ULONG i;
2779
2780 for( i = 1; i < ImageSectionObject->NrSegments; ++ i )
2781 {
2782 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
2783 ImageSectionObject->Segments[i - 1].VirtualAddress);
2784 }
2785 }
2786
2787 static
2788 VOID
2789 NTAPI
2790 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2791 {
2792 ULONG i;
2793
2794 MmspAssertSegmentsSorted(ImageSectionObject);
2795
2796 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2797 {
2798 ASSERT(ImageSectionObject->Segments[i].Length > 0);
2799
2800 if(i > 0)
2801 {
2802 ASSERT(ImageSectionObject->Segments[i].VirtualAddress >=
2803 (ImageSectionObject->Segments[i - 1].VirtualAddress +
2804 ImageSectionObject->Segments[i - 1].Length));
2805 }
2806 }
2807 }
2808
2809 static
2810 VOID
2811 NTAPI
2812 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
2813 {
2814 ULONG i;
2815
2816 for( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2817 {
2818 ASSERT((ImageSectionObject->Segments[i].VirtualAddress % PAGE_SIZE) == 0);
2819 ASSERT((ImageSectionObject->Segments[i].Length % PAGE_SIZE) == 0);
2820 }
2821 }
2822 #endif
2823
2824 static
2825 int
2826 __cdecl
2827 MmspCompareSegments(const void * x,
2828 const void * y)
2829 {
2830 const MM_SECTION_SEGMENT *Segment1 = (const MM_SECTION_SEGMENT *)x;
2831 const MM_SECTION_SEGMENT *Segment2 = (const MM_SECTION_SEGMENT *)y;
2832
2833 return
2834 (Segment1->VirtualAddress - Segment2->VirtualAddress) >>
2835 ((sizeof(ULONG_PTR) - sizeof(int)) * 8);
2836 }
2837
2838 /*
2839 * Ensures an image section's segments are sorted in memory
2840 */
2841 static
2842 VOID
2843 NTAPI
2844 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2845 IN ULONG Flags)
2846 {
2847 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED)
2848 {
2849 MmspAssertSegmentsSorted(ImageSectionObject);
2850 }
2851 else
2852 {
2853 qsort(ImageSectionObject->Segments,
2854 ImageSectionObject->NrSegments,
2855 sizeof(ImageSectionObject->Segments[0]),
2856 MmspCompareSegments);
2857 }
2858 }
2859
2860
2861 /*
2862 * Ensures an image section's segments don't overlap in memory and don't have
2863 * gaps and don't have a null size. We let them map to overlapping file regions,
2864 * though - that's not necessarily an error
2865 */
2866 static
2867 BOOLEAN
2868 NTAPI
2869 MmspCheckSegmentBounds
2870 (
2871 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2872 IN ULONG Flags
2873 )
2874 {
2875 ULONG i;
2876
2877 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP)
2878 {
2879 MmspAssertSegmentsNoOverlap(ImageSectionObject);
2880 return TRUE;
2881 }
2882
2883 ASSERT(ImageSectionObject->NrSegments >= 1);
2884
2885 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2886 {
2887 if(ImageSectionObject->Segments[i].Length == 0)
2888 {
2889 return FALSE;
2890 }
2891
2892 if(i > 0)
2893 {
2894 /*
2895 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2896 * page could be OK (Windows seems to be OK with them), and larger gaps
2897 * could lead to image sections spanning several discontiguous regions
2898 * (NtMapViewOfSection could then refuse to map them, and they could
2899 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2900 */
2901 if ((ImageSectionObject->Segments[i - 1].VirtualAddress +
2902 ImageSectionObject->Segments[i - 1].Length) !=
2903 ImageSectionObject->Segments[i].VirtualAddress)
2904 {
2905 return FALSE;
2906 }
2907 }
2908 }
2909
2910 return TRUE;
2911 }
2912
2913 /*
2914 * Merges and pads an image section's segments until they all are page-aligned
2915 * and have a size that is a multiple of the page size
2916 */
2917 static
2918 BOOLEAN
2919 NTAPI
2920 MmspPageAlignSegments
2921 (
2922 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
2923 IN ULONG Flags
2924 )
2925 {
2926 ULONG i;
2927 ULONG LastSegment;
2928 BOOLEAN Initialized;
2929 PMM_SECTION_SEGMENT EffectiveSegment;
2930
2931 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
2932 {
2933 MmspAssertSegmentsPageAligned(ImageSectionObject);
2934 return TRUE;
2935 }
2936
2937 Initialized = FALSE;
2938 LastSegment = 0;
2939 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2940
2941 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2942 {
2943 /*
2944 * The first segment requires special handling
2945 */
2946 if (i == 0)
2947 {
2948 ULONG_PTR VirtualAddress;
2949 ULONG_PTR VirtualOffset;
2950
2951 VirtualAddress = EffectiveSegment->VirtualAddress;
2952
2953 /* Round down the virtual address to the nearest page */
2954 EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
2955
2956 /* Round up the virtual size to the nearest page */
2957 EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
2958 EffectiveSegment->VirtualAddress;
2959
2960 /* Adjust the raw address and size */
2961 VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
2962
2963 if (EffectiveSegment->FileOffset < VirtualOffset)
2964 {
2965 return FALSE;
2966 }
2967
2968 /*
2969 * Garbage in, garbage out: unaligned base addresses make the file
2970 * offset point in curious and odd places, but that's what we were
2971 * asked for
2972 */
2973 EffectiveSegment->FileOffset -= VirtualOffset;
2974 EffectiveSegment->RawLength += VirtualOffset;
2975 }
2976 else
2977 {
2978 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
2979 ULONG_PTR EndOfEffectiveSegment;
2980
2981 EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
2982 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
2983
2984 /*
2985 * The current segment begins exactly where the current effective
2986 * segment ended, therefore beginning a new effective segment
2987 */
2988 if (EndOfEffectiveSegment == Segment->VirtualAddress)
2989 {
2990 LastSegment ++;
2991 ASSERT(LastSegment <= i);
2992 ASSERT(LastSegment < ImageSectionObject->NrSegments);
2993
2994 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2995
2996 if (LastSegment != i)
2997 {
2998 /*
2999 * Copy the current segment. If necessary, the effective segment
3000 * will be expanded later
3001 */
3002 *EffectiveSegment = *Segment;
3003 }
3004
3005 /*
3006 * Page-align the virtual size. We know for sure the virtual address
3007 * already is
3008 */
3009 ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
3010 EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
3011 }
3012 /*
3013 * The current segment is still part of the current effective segment:
3014 * extend the effective segment to reflect this
3015 */
3016 else if (EndOfEffectiveSegment > Segment->VirtualAddress)
3017 {
3018 static const ULONG FlagsToProtection[16] =
3019 {
3020 PAGE_NOACCESS,
3021 PAGE_READONLY,
3022 PAGE_READWRITE,
3023 PAGE_READWRITE,
3024 PAGE_EXECUTE_READ,
3025 PAGE_EXECUTE_READ,
3026 PAGE_EXECUTE_READWRITE,
3027 PAGE_EXECUTE_READWRITE,
3028 PAGE_WRITECOPY,
3029 PAGE_WRITECOPY,
3030 PAGE_WRITECOPY,
3031 PAGE_WRITECOPY,
3032 PAGE_EXECUTE_WRITECOPY,
3033 PAGE_EXECUTE_WRITECOPY,
3034 PAGE_EXECUTE_WRITECOPY,
3035 PAGE_EXECUTE_WRITECOPY
3036 };
3037
3038 unsigned ProtectionFlags;
3039
3040 /*
3041 * Extend the file size
3042 */
3043
3044 /* Unaligned segments must be contiguous within the file */
3045 if (Segment->FileOffset != (EffectiveSegment->FileOffset +
3046 EffectiveSegment->RawLength))
3047 {
3048 return FALSE;
3049 }
3050
3051 EffectiveSegment->RawLength += Segment->RawLength;
3052
3053 /*
3054 * Extend the virtual size
3055 */
3056 ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
3057
3058 EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
3059 EffectiveSegment->VirtualAddress;
3060
3061 /*
3062 * Merge the protection
3063 */
3064 EffectiveSegment->Protection |= Segment->Protection;
3065
3066 /* Clean up redundance */
3067 ProtectionFlags = 0;
3068
3069 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3070 ProtectionFlags |= 1 << 0;
3071
3072 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3073 ProtectionFlags |= 1 << 1;
3074
3075 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3076 ProtectionFlags |= 1 << 2;
3077
3078 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3079 ProtectionFlags |= 1 << 3;
3080
3081 ASSERT(ProtectionFlags < 16);
3082 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3083
3084 /* If a segment was required to be shared and cannot, fail */
3085 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3086 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3087 {
3088 return FALSE;
3089 }
3090 }
3091 /*
3092 * We assume no holes between segments at this point
3093 */
3094 else
3095 {
3096 ASSERT(FALSE);
3097 }
3098 }
3099 }
3100 ImageSectionObject->NrSegments = LastSegment + 1;
3101
3102 return TRUE;
3103 }
3104
3105 NTSTATUS
3106 ExeFmtpCreateImageSection(HANDLE FileHandle,
3107 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3108 {
3109 LARGE_INTEGER Offset;
3110 PVOID FileHeader;
3111 PVOID FileHeaderBuffer;
3112 ULONG FileHeaderSize;
3113 ULONG Flags;
3114 ULONG OldNrSegments;
3115 NTSTATUS Status;
3116 ULONG i;
3117
3118 /*
3119 * Read the beginning of the file (2 pages). Should be enough to contain
3120 * all (or most) of the headers
3121 */
3122 Offset.QuadPart = 0;
3123
3124 /* FIXME: use FileObject instead of FileHandle */
3125 Status = ExeFmtpReadFile (FileHandle,
3126 &Offset,
3127 PAGE_SIZE * 2,
3128 &FileHeader,
3129 &FileHeaderBuffer,
3130 &FileHeaderSize);
3131
3132 if (!NT_SUCCESS(Status))
3133 return Status;
3134
3135 if (FileHeaderSize == 0)
3136 {
3137 ExFreePool(FileHeaderBuffer);
3138 return STATUS_UNSUCCESSFUL;
3139 }
3140
3141 /*
3142 * Look for a loader that can handle this executable
3143 */
3144 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3145 {
3146 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3147 Flags = 0;
3148
3149 /* FIXME: use FileObject instead of FileHandle */
3150 Status = ExeFmtpLoaders[i](FileHeader,
3151 FileHeaderSize,
3152 FileHandle,
3153 ImageSectionObject,
3154 &Flags,
3155 ExeFmtpReadFile,
3156 ExeFmtpAllocateSegments);
3157
3158 if (!NT_SUCCESS(Status))
3159 {
3160 if (ImageSectionObject->Segments)
3161 {
3162 ExFreePool(ImageSectionObject->Segments);
3163 ImageSectionObject->Segments = NULL;
3164 }
3165 }
3166
3167 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3168 break;
3169 }
3170
3171 ExFreePool(FileHeaderBuffer);
3172
3173 /*
3174 * No loader handled the format
3175 */
3176 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3177 {
3178 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3179 ASSERT(!NT_SUCCESS(Status));
3180 }
3181
3182 if (!NT_SUCCESS(Status))
3183 return Status;
3184
3185 ASSERT(ImageSectionObject->Segments != NULL);
3186
3187 /*
3188 * Some defaults
3189 */
3190 /* FIXME? are these values platform-dependent? */
3191 if(ImageSectionObject->StackReserve == 0)
3192 ImageSectionObject->StackReserve = 0x40000;
3193
3194 if(ImageSectionObject->StackCommit == 0)
3195 ImageSectionObject->StackCommit = 0x1000;
3196
3197 if(ImageSectionObject->ImageBase == 0)
3198 {
3199 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3200 ImageSectionObject->ImageBase = 0x10000000;
3201 else
3202 ImageSectionObject->ImageBase = 0x00400000;
3203 }
3204
3205 /*
3206 * And now the fun part: fixing the segments
3207 */
3208
3209 /* Sort them by virtual address */
3210 MmspSortSegments(ImageSectionObject, Flags);
3211
3212 /* Ensure they don't overlap in memory */
3213 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3214 return STATUS_INVALID_IMAGE_FORMAT;
3215
3216 /* Ensure they are aligned */
3217 OldNrSegments = ImageSectionObject->NrSegments;
3218
3219 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3220 return STATUS_INVALID_IMAGE_FORMAT;
3221
3222 /* Trim them if the alignment phase merged some of them */
3223 if (ImageSectionObject->NrSegments < OldNrSegments)
3224 {
3225 PMM_SECTION_SEGMENT Segments;
3226 SIZE_T SizeOfSegments;
3227
3228 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3229
3230 Segments = ExAllocatePoolWithTag(PagedPool,
3231 SizeOfSegments,
3232 TAG_MM_SECTION_SEGMENT);
3233
3234 if (Segments == NULL)
3235 return STATUS_INSUFFICIENT_RESOURCES;
3236
3237 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3238 ExFreePool(ImageSectionObject->Segments);
3239 ImageSectionObject->Segments = Segments;
3240 }
3241
3242 /* And finish their initialization */
3243 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3244 {
3245 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3246 ImageSectionObject->Segments[i].ReferenceCount = 1;
3247
3248 RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
3249 sizeof(ImageSectionObject->Segments[i].PageDirectory));
3250 }
3251
3252 ASSERT(NT_SUCCESS(Status));
3253 return Status;
3254 }
3255
3256 NTSTATUS
3257 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3258 ACCESS_MASK DesiredAccess,
3259 POBJECT_ATTRIBUTES ObjectAttributes,
3260 PLARGE_INTEGER UMaximumSize,
3261 ULONG SectionPageProtection,
3262 ULONG AllocationAttributes,
3263 HANDLE FileHandle)
3264 {
3265 PROS_SECTION_OBJECT Section;
3266 NTSTATUS Status;
3267 PFILE_OBJECT FileObject;
3268 PMM_SECTION_SEGMENT SectionSegments;
3269 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3270 ULONG i;
3271 ULONG FileAccess = 0;
3272
3273 /*
3274 * Specifying a maximum size is meaningless for an image section
3275 */
3276 if (UMaximumSize != NULL)
3277 {
3278 return(STATUS_INVALID_PARAMETER_4);
3279 }
3280
3281 /*
3282 * Check file access required
3283 */
3284 if (SectionPageProtection & PAGE_READWRITE ||
3285 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3286 {
3287 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3288 }
3289 else
3290 {
3291 FileAccess = FILE_READ_DATA;
3292 }
3293
3294 /*
3295 * Reference the file handle
3296 */
3297 Status = ObReferenceObjectByHandle(FileHandle,
3298 FileAccess,
3299 IoFileObjectType,
3300 ExGetPreviousMode(),
3301 (PVOID*)(PVOID)&FileObject,
3302 NULL);
3303
3304 if (!NT_SUCCESS(Status))
3305 {
3306 return Status;
3307 }
3308
3309 /*
3310 * Create the section
3311 */
3312 Status = ObCreateObject (ExGetPreviousMode(),
3313 MmSectionObjectType,
3314 ObjectAttributes,
3315 ExGetPreviousMode(),
3316 NULL,
3317 sizeof(ROS_SECTION_OBJECT),
3318 0,
3319 0,
3320 (PVOID*)(PVOID)&Section);
3321 if (!NT_SUCCESS(Status))
3322 {
3323 ObDereferenceObject(FileObject);
3324 return(Status);
3325 }
3326
3327 /*
3328 * Initialize it
3329 */
3330 Section->SectionPageProtection = SectionPageProtection;
3331 Section->AllocationAttributes = AllocationAttributes;
3332
3333 /*
3334 * Initialized caching for this file object if previously caching
3335 * was initialized for the same on disk file
3336 */
3337 Status = CcTryToInitializeFileCache(FileObject);
3338
3339 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3340 {
3341 NTSTATUS StatusExeFmt;
3342
3343 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3344 if (ImageSectionObject == NULL)
3345 {
3346 ObDereferenceObject(FileObject);
3347 ObDereferenceObject(Section);
3348 return(STATUS_NO_MEMORY);
3349 }
3350
3351 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3352
3353 StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
3354
3355 if (!NT_SUCCESS(StatusExeFmt))
3356 {
3357 if(ImageSectionObject->Segments != NULL)
3358 ExFreePool(ImageSectionObject->Segments);
3359
3360 ExFreePool(ImageSectionObject);
3361 ObDereferenceObject(Section);
3362 ObDereferenceObject(FileObject);
3363 return(StatusExeFmt);
3364 }
3365
3366 Section->ImageSection = ImageSectionObject;
3367 ASSERT(ImageSectionObject->Segments);
3368
3369 /*
3370 * Lock the file
3371 */
3372 Status = MmspWaitForFileLock(FileObject);
3373 if (!NT_SUCCESS(Status))
3374 {
3375 ExFreePool(ImageSectionObject->Segments);
3376 ExFreePool(ImageSectionObject);
3377 ObDereferenceObject(Section);
3378 ObDereferenceObject(FileObject);
3379 return(Status);
3380 }
3381
3382 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3383 ImageSectionObject, NULL))
3384 {
3385 /*
3386 * An other thread has initialized the some image in the background
3387 */
3388 ExFreePool(ImageSectionObject->Segments);
3389 ExFreePool(ImageSectionObject);
3390 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3391 Section->ImageSection = ImageSectionObject;
3392 SectionSegments = ImageSectionObject->Segments;
3393
3394 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3395 {
3396 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3397 }
3398 }
3399
3400 Status = StatusExeFmt;
3401 }
3402 else
3403 {
3404 /*
3405 * Lock the file
3406 */
3407 Status = MmspWaitForFileLock(FileObject);
3408 if (Status != STATUS_SUCCESS)
3409 {
3410 ObDereferenceObject(Section);
3411 ObDereferenceObject(FileObject);
3412 return(Status);
3413 }
3414
3415 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3416 Section->ImageSection = ImageSectionObject;
3417 SectionSegments = ImageSectionObject->Segments;
3418
3419 /*
3420 * Otherwise just reference all the section segments
3421 */
3422 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3423 {
3424 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3425 }
3426
3427 Status = STATUS_SUCCESS;
3428 }
3429 Section->FileObject = FileObject;
3430 CcRosReferenceCache(FileObject);
3431 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3432 *SectionObject = Section;
3433 return(Status);
3434 }
3435
3436 /*
3437 * @implemented
3438 */
3439 NTSTATUS STDCALL
3440 NtCreateSection (OUT PHANDLE SectionHandle,
3441 IN ACCESS_MASK DesiredAccess,
3442 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3443 IN PLARGE_INTEGER MaximumSize OPTIONAL,
3444 IN ULONG SectionPageProtection OPTIONAL,
3445 IN ULONG AllocationAttributes,
3446 IN HANDLE FileHandle OPTIONAL)
3447 {
3448 LARGE_INTEGER SafeMaximumSize;
3449 PVOID SectionObject;
3450 KPROCESSOR_MODE PreviousMode;
3451 NTSTATUS Status = STATUS_SUCCESS;
3452
3453 PreviousMode = ExGetPreviousMode();
3454
3455 if(MaximumSize != NULL && PreviousMode != KernelMode)
3456 {
3457 _SEH_TRY
3458 {
3459 /* make a copy on the stack */
3460 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
3461 MaximumSize = &SafeMaximumSize;
3462 }
3463 _SEH_HANDLE
3464 {
3465 Status = _SEH_GetExceptionCode();
3466 }
3467 _SEH_END;
3468
3469 if(!NT_SUCCESS(Status))
3470 {
3471 return Status;
3472 }
3473 }
3474
3475 Status = MmCreateSection(&SectionObject,
3476 DesiredAccess,
3477 ObjectAttributes,
3478 MaximumSize,
3479 SectionPageProtection,
3480 AllocationAttributes,
3481 FileHandle,
3482 NULL);
3483 if (NT_SUCCESS(Status))
3484 {
3485 Status = ObInsertObject ((PVOID)SectionObject,
3486 NULL,
3487 DesiredAccess,
3488 0,
3489 NULL,
3490 SectionHandle);
3491 }
3492
3493 return Status;
3494 }
3495
3496
3497 /**********************************************************************
3498 * NAME
3499 * NtOpenSection
3500 *
3501 * DESCRIPTION
3502 *
3503 * ARGUMENTS
3504 * SectionHandle
3505 *
3506 * DesiredAccess
3507 *
3508 * ObjectAttributes
3509 *
3510 * RETURN VALUE
3511 *
3512 * REVISIONS
3513 */
3514 NTSTATUS STDCALL
3515 NtOpenSection(PHANDLE SectionHandle,
3516 ACCESS_MASK DesiredAccess,
3517 POBJECT_ATTRIBUTES ObjectAttributes)
3518 {
3519 HANDLE hSection;
3520 KPROCESSOR_MODE PreviousMode;
3521 NTSTATUS Status = STATUS_SUCCESS;
3522
3523 PreviousMode = ExGetPreviousMode();
3524
3525 if(PreviousMode != KernelMode)
3526 {
3527 _SEH_TRY
3528 {
3529 ProbeForWriteHandle(SectionHandle);
3530 }
3531 _SEH_HANDLE
3532 {
3533 Status = _SEH_GetExceptionCode();
3534 }
3535 _SEH_END;
3536
3537 if(!NT_SUCCESS(Status))
3538 {
3539 return Status;
3540 }
3541 }
3542
3543 Status = ObOpenObjectByName(ObjectAttributes,
3544 MmSectionObjectType,
3545 PreviousMode,
3546 NULL,
3547 DesiredAccess,
3548 NULL,
3549 &hSection);
3550
3551 if(NT_SUCCESS(Status))
3552 {
3553 _SEH_TRY
3554 {
3555 *SectionHandle = hSection;
3556 }
3557 _SEH_HANDLE
3558 {
3559 Status = _SEH_GetExceptionCode();
3560 }
3561 _SEH_END;
3562 }
3563
3564 return(Status);
3565 }
3566
3567 NTSTATUS static
3568 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace,
3569 PROS_SECTION_OBJECT Section,
3570 PMM_SECTION_SEGMENT Segment,
3571 PVOID* BaseAddress,
3572 SIZE_T ViewSize,
3573 ULONG Protect,
3574 ULONG ViewOffset,
3575 ULONG AllocationType)
3576 {
3577 PMEMORY_AREA MArea;
3578 NTSTATUS Status;
3579 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3580
3581 BoundaryAddressMultiple.QuadPart = 0;
3582
3583 Status = MmCreateMemoryArea(AddressSpace,
3584 MEMORY_AREA_SECTION_VIEW,
3585 BaseAddress,
3586 ViewSize,
3587 Protect,
3588 &MArea,
3589 FALSE,
3590 AllocationType,
3591 BoundaryAddressMultiple);
3592 if (!NT_SUCCESS(Status))
3593 {
3594 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3595 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3596 return(Status);
3597 }
3598
3599 ObReferenceObject((PVOID)Section);
3600
3601 MArea->Data.SectionData.Segment = Segment;
3602 MArea->Data.SectionData.Section = Section;
3603 MArea->Data.SectionData.ViewOffset = ViewOffset;
3604 MArea->Data.SectionData.WriteCopyView = FALSE;
3605 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
3606 ViewSize, 0, Protect);
3607
3608 return(STATUS_SUCCESS);
3609 }
3610
3611
3612 /**********************************************************************
3613 * NAME EXPORTED
3614 * NtMapViewOfSection
3615 *
3616 * DESCRIPTION
3617 * Maps a view of a section into the virtual address space of a
3618 * process.
3619 *
3620 * ARGUMENTS
3621 * SectionHandle
3622 * Handle of the section.
3623 *
3624 * ProcessHandle
3625 * Handle of the process.
3626 *
3627 * BaseAddress
3628 * Desired base address (or NULL) on entry;
3629 * Actual base address of the view on exit.
3630 *
3631 * ZeroBits
3632 * Number of high order address bits that must be zero.
3633 *
3634 * CommitSize
3635 * Size in bytes of the initially committed section of
3636 * the view.
3637 *
3638 * SectionOffset
3639 * Offset in bytes from the beginning of the section
3640 * to the beginning of the view.
3641 *
3642 * ViewSize
3643 * Desired length of map (or zero to map all) on entry
3644 * Actual length mapped on exit.
3645 *
3646 * InheritDisposition
3647 * Specified how the view is to be shared with
3648 * child processes.
3649 *
3650 * AllocateType
3651 * Type of allocation for the pages.
3652 *
3653 * Protect
3654 * Protection for the committed region of the view.
3655 *
3656 * RETURN VALUE
3657 * Status.
3658 *
3659 * @implemented
3660 */
3661 NTSTATUS STDCALL
3662 NtMapViewOfSection(IN HANDLE SectionHandle,
3663 IN HANDLE ProcessHandle,
3664 IN OUT PVOID* BaseAddress OPTIONAL,
3665 IN ULONG ZeroBits OPTIONAL,
3666 IN ULONG CommitSize,
3667 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3668 IN OUT PSIZE_T ViewSize,
3669 IN SECTION_INHERIT InheritDisposition,
3670 IN ULONG AllocationType OPTIONAL,
3671 IN ULONG Protect)
3672 {
3673 PVOID SafeBaseAddress;
3674 LARGE_INTEGER SafeSectionOffset;
3675 SIZE_T SafeViewSize;
3676 PROS_SECTION_OBJECT Section;
3677 PEPROCESS Process;
3678 KPROCESSOR_MODE PreviousMode;
3679 PMM_AVL_TABLE AddressSpace;
3680 NTSTATUS Status = STATUS_SUCCESS;
3681 ULONG tmpProtect;
3682
3683 /*
3684 * Check the protection
3685 */
3686 if (Protect & ~PAGE_FLAGS_VALID_FROM_USER_MODE)
3687 {
3688 return STATUS_INVALID_PARAMETER_10;
3689 }
3690
3691 tmpProtect = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
3692 if (tmpProtect != PAGE_NOACCESS &&
3693 tmpProtect != PAGE_READONLY &&
3694 tmpProtect != PAGE_READWRITE &&
3695 tmpProtect != PAGE_WRITECOPY &&
3696 tmpProtect != PAGE_EXECUTE &&
3697 tmpProtect != PAGE_EXECUTE_READ &&
3698 tmpProtect != PAGE_EXECUTE_READWRITE &&
3699 tmpProtect != PAGE_EXECUTE_WRITECOPY)
3700 {
3701 return STATUS_INVALID_PAGE_PROTECTION;
3702 }
3703
3704 PreviousMode = ExGetPreviousMode();
3705
3706 if(PreviousMode != KernelMode)
3707 {
3708 SafeBaseAddress = NULL;
3709 SafeSectionOffset.QuadPart = 0;
3710 SafeViewSize = 0;
3711
3712 _SEH_TRY
3713 {
3714 if(BaseAddress != NULL)
3715 {
3716 ProbeForWritePointer(BaseAddress);
3717 SafeBaseAddress = *BaseAddress;
3718 }
3719 if(SectionOffset != NULL)
3720 {
3721 ProbeForWriteLargeInteger(SectionOffset);
3722 SafeSectionOffset = *SectionOffset;
3723 }
3724 ProbeForWriteSize_t(ViewSize);
3725 SafeViewSize = *ViewSize;
3726 }
3727 _SEH_HANDLE
3728 {
3729 Status = _SEH_GetExceptionCode();
3730 }
3731 _SEH_END;
3732
3733 if(!NT_SUCCESS(Status))
3734 {
3735 return Status;
3736 }
3737 }
3738 else
3739 {
3740 SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
3741 SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
3742 SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
3743 }
3744
3745 SafeSectionOffset.LowPart = PAGE_ROUND_DOWN(SafeSectionOffset.LowPart);
3746
3747 Status = ObReferenceObjectByHandle(ProcessHandle,
3748 PROCESS_VM_OPERATION,
3749 PsProcessType,
3750 PreviousMode,
3751 (PVOID*)(PVOID)&Process,
3752 NULL);
3753 if (!NT_SUCCESS(Status))
3754 {
3755 return(Status);
3756 }
3757
3758 AddressSpace = &Process->VadRoot;
3759
3760 Status = ObReferenceObjectByHandle(SectionHandle,
3761 SECTION_MAP_READ,
3762 MmSectionObjectType,
3763 PreviousMode,
3764 (PVOID*)(PVOID)&Section,
3765 NULL);
3766 if (!(NT_SUCCESS(Status)))
3767 {
3768 DPRINT("ObReference failed rc=%x\n",Status);
3769 ObDereferenceObject(Process);
3770 return(Status);
3771 }
3772
3773 Status = MmMapViewOfSection(Section,
3774 (PEPROCESS)Process,
3775 (BaseAddress != NULL ? &SafeBaseAddress : NULL),
3776 ZeroBits,
3777 CommitSize,
3778 (SectionOffset != NULL ? &SafeSectionOffset : NULL),
3779 (ViewSize != NULL ? &SafeViewSize : NULL),
3780 InheritDisposition,
3781 AllocationType,
3782 Protect);
3783
3784 /* Check if this is an image for the current process */
3785 if ((Section->AllocationAttributes & SEC_IMAGE) &&
3786 (Process == PsGetCurrentProcess()) &&
3787 (Status != STATUS_IMAGE_NOT_AT_BASE))
3788 {
3789 /* Notify the debugger */
3790 DbgkMapViewOfSection(Section,
3791 SafeBaseAddress,
3792 SafeSectionOffset.LowPart,
3793 SafeViewSize);
3794 }
3795
3796 ObDereferenceObject(Section);
3797 ObDereferenceObject(Process);
3798
3799 if(NT_SUCCESS(Status))
3800 {
3801 /* copy parameters back to the caller */
3802 _SEH_TRY
3803 {
3804 if(BaseAddress != NULL)
3805 {
3806 *BaseAddress = SafeBaseAddress;
3807 }
3808 if(SectionOffset != NULL)
3809 {
3810 *SectionOffset = SafeSectionOffset;
3811 }
3812 if(ViewSize != NULL)
3813 {
3814 *ViewSize = SafeViewSize;
3815 }
3816 }
3817 _SEH_HANDLE
3818 {
3819 Status = _SEH_GetExceptionCode();
3820 }
3821 _SEH_END;
3822 }
3823
3824 return(Status);
3825 }
3826
3827 VOID static
3828 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3829 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3830 {
3831 ULONG Entry;
3832 PFILE_OBJECT FileObject;
3833 PBCB Bcb;
3834 ULONG Offset;
3835 SWAPENTRY SavedSwapEntry;
3836 PMM_PAGEOP PageOp;
3837 NTSTATUS Status;
3838 PROS_SECTION_OBJECT Section;
3839 PMM_SECTION_SEGMENT Segment;
3840 PMM_AVL_TABLE AddressSpace;
3841 PEPROCESS Process;
3842
3843 AddressSpace = (PMM_AVL_TABLE)Context;
3844 Process = MmGetAddressSpaceOwner(AddressSpace);
3845
3846 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3847
3848 Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
3849 MemoryArea->Data.SectionData.ViewOffset;
3850
3851 Section = MemoryArea->Data.SectionData.Section;
3852 Segment = MemoryArea->Data.SectionData.Segment;
3853
3854 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3855
3856 while (PageOp)
3857 {
3858 MmUnlockSectionSegment(Segment);
3859 MmUnlockAddressSpace(AddressSpace);
3860
3861 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3862 if (Status != STATUS_SUCCESS)
3863 {
3864 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3865 ASSERT(FALSE);
3866 }
3867
3868 MmLockAddressSpace(AddressSpace);
3869 MmLockSectionSegment(Segment);
3870 MmspCompleteAndReleasePageOp(PageOp);
3871 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3872 }
3873
3874 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3875
3876 /*
3877 * For a dirty, datafile, non-private page mark it as dirty in the
3878 * cache manager.
3879 */
3880 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3881 {
3882 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3883 {
3884 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3885 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3886 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
3887 ASSERT(SwapEntry == 0);
3888 }
3889 }
3890
3891 if (SwapEntry != 0)
3892 {
3893 /*
3894 * Sanity check
3895 */
3896 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3897 {
3898 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3899 ASSERT(FALSE);
3900 }
3901 MmFreeSwapPage(SwapEntry);
3902 }
3903 else if (Page != 0)
3904 {
3905 if (IS_SWAP_FROM_SSE(Entry) ||
3906 Page != PFN_FROM_SSE(Entry))
3907 {
3908 /*
3909 * Sanity check
3910 */
3911 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3912 {
3913 DPRINT1("Found a private page in a pagefile section.\n");
3914 ASSERT(FALSE);
3915 }
3916 /*
3917 * Just dereference private pages
3918 */
3919 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3920 if (SavedSwapEntry != 0)
3921 {
3922 MmFreeSwapPage(SavedSwapEntry);
3923 MmSetSavedSwapEntryPage(Page, 0);
3924 }
3925 MmDeleteRmap(Page, Process, Address);
3926 MmReleasePageMemoryConsumer(MC_USER, Page);
3927 }
3928 else
3929 {
3930 MmDeleteRmap(Page, Process, Address);
3931 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3932 }
3933 }
3934 }
3935
3936 static NTSTATUS
3937 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace,
3938 PVOID BaseAddress)
3939 {
3940 NTSTATUS Status;
3941 PMEMORY_AREA MemoryArea;
3942 PROS_SECTION_OBJECT Section;
3943 PMM_SECTION_SEGMENT Segment;
3944 PLIST_ENTRY CurrentEntry;
3945 PMM_REGION CurrentRegion;
3946 PLIST_ENTRY RegionListHead;
3947
3948 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3949 BaseAddress);
3950 if (MemoryArea == NULL)
3951 {
3952 return(STATUS_UNSUCCESSFUL);
3953 }
3954
3955 MemoryArea->DeleteInProgress = TRUE;
3956 Section = MemoryArea->Data.SectionData.Section;
3957 Segment = MemoryArea->Data.SectionData.Segment;
3958
3959 MmLockSectionSegment(Segment);
3960
3961 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3962 while (!IsListEmpty(RegionListHead))
3963 {
3964 CurrentEntry = RemoveHeadList(RegionListHead);
3965 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3966 ExFreePool(CurrentRegion);
3967 }
3968
3969 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3970 {
3971 Status = MmFreeMemoryArea(AddressSpace,
3972 MemoryArea,
3973 NULL,
3974 NULL);
3975 }
3976 else
3977 {
3978 Status = MmFreeMemoryArea(AddressSpace,
3979 MemoryArea,
3980 MmFreeSectionPage,
3981 AddressSpace);
3982 }
3983 MmUnlockSectionSegment(Segment);
3984 ObDereferenceObject(Section);
3985 return(STATUS_SUCCESS);
3986 }
3987
3988 /*
3989 * @implemented
3990 */
3991 NTSTATUS STDCALL
3992 MmUnmapViewOfSection(PEPROCESS Process,
3993 PVOID BaseAddress)
3994 {
3995 NTSTATUS Status;
3996 PMEMORY_AREA MemoryArea;
3997 PMM_AVL_TABLE AddressSpace;
3998 PROS_SECTION_OBJECT Section;
3999 PMM_PAGEOP PageOp;
4000 ULONG_PTR Offset;
4001 PVOID ImageBaseAddress = 0;
4002
4003 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4004 Process, BaseAddress);
4005
4006 ASSERT(Process);
4007
4008 AddressSpace = &Process->VadRoot;
4009
4010 MmLockAddressSpace(AddressSpace);
4011 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4012 BaseAddress);
4013 if (MemoryArea == NULL ||
4014 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4015 MemoryArea->DeleteInProgress)
4016 {
4017 MmUnlockAddressSpace(AddressSpace);
4018 return STATUS_NOT_MAPPED_VIEW;
4019 }
4020
4021 MemoryArea->DeleteInProgress = TRUE;
4022
4023 while (MemoryArea->PageOpCount)
4024 {
4025 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4026
4027 while (Offset)
4028 {
4029 Offset -= PAGE_SIZE;
4030 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4031 MemoryArea->Data.SectionData.Segment,
4032 Offset + MemoryArea->Data.SectionData.ViewOffset);
4033 if (PageOp)
4034 {
4035 MmUnlockAddressSpace(AddressSpace);
4036 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4037 if (Status != STATUS_SUCCESS)
4038 {
4039 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4040 ASSERT(FALSE);
4041 }
4042 MmLockAddressSpace(AddressSpace);
4043 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4044 BaseAddress);
4045 if (MemoryArea == NULL ||
4046 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4047 {
4048 MmUnlockAddressSpace(AddressSpace);
4049 return STATUS_NOT_MAPPED_VIEW;
4050 }
4051 break;
4052 }
4053 }
4054 }
4055
4056 Section = MemoryArea->Data.SectionData.Section;
4057
4058 if (Section->AllocationAttributes & SEC_IMAGE)
4059 {
4060 ULONG i;
4061 ULONG NrSegments;
4062 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4063 PMM_SECTION_SEGMENT SectionSegments;
4064 PMM_SECTION_SEGMENT Segment;
4065
4066 Segment = MemoryArea->Data.SectionData.Segment;
4067 ImageSectionObject = Section->ImageSection;
4068 SectionSegments = ImageSectionObject->Segments;
4069 NrSegments = ImageSectionObject->NrSegments;
4070
4071 /* Search for the current segment within the section segments
4072 * and calculate the image base address */
4073 for (i = 0; i < NrSegments; i++)
4074 {
4075 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4076 {
4077 if (Segment == &SectionSegments[i])
4078 {
4079 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
4080 break;
4081 }
4082 }
4083 }
4084 if (i >= NrSegments)
4085 {
4086 ASSERT(FALSE);
4087 }
4088
4089 for (i = 0; i < NrSegments; i++)
4090 {
4091 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4092 {
4093 PVOID SBaseAddress = (PVOID)
4094 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4095
4096 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4097 }
4098 }
4099 }
4100 else
4101 {
4102 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4103 }
4104
4105 /* Notify debugger */
4106 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4107
4108 MmUnlockAddressSpace(AddressSpace);
4109 return(STATUS_SUCCESS);
4110 }
4111
4112 /**********************************************************************
4113 * NAME EXPORTED
4114 * NtUnmapViewOfSection
4115 *
4116 * DESCRIPTION
4117 *
4118 * ARGUMENTS
4119 * ProcessHandle
4120 *
4121 * BaseAddress
4122 *
4123 * RETURN VALUE
4124 * Status.
4125 *
4126 * REVISIONS
4127 */
4128 NTSTATUS STDCALL
4129 NtUnmapViewOfSection (HANDLE ProcessHandle,
4130 PVOID BaseAddress)
4131 {
4132 PEPROCESS Process;
4133 KPROCESSOR_MODE PreviousMode;
4134 NTSTATUS Status;
4135
4136 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4137 ProcessHandle, BaseAddress);
4138
4139 PreviousMode = ExGetPreviousMode();
4140
4141 DPRINT("Referencing process\n");
4142 Status = ObReferenceObjectByHandle(ProcessHandle,
4143 PROCESS_VM_OPERATION,
4144 PsProcessType,
4145 PreviousMode,
4146 (PVOID*)(PVOID)&Process,
4147 NULL);
4148 if (!NT_SUCCESS(Status))
4149 {
4150 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
4151 return(Status);
4152 }
4153
4154 Status = MmUnmapViewOfSection(Process, BaseAddress);
4155
4156 ObDereferenceObject(Process);
4157
4158 return Status;
4159 }
4160
4161
4162 /**
4163 * Queries the information of a section object.
4164 *
4165 * @param SectionHandle
4166 * Handle to the section object. It must be opened with SECTION_QUERY
4167 * access.
4168 * @param SectionInformationClass
4169 * Index to a certain information structure. Can be either
4170 * SectionBasicInformation or SectionImageInformation. The latter
4171 * is valid only for sections that were created with the SEC_IMAGE
4172 * flag.
4173 * @param SectionInformation
4174 * Caller supplies storage for resulting information.
4175 * @param Length
4176 * Size of the supplied storage.
4177 * @param ResultLength
4178 * Data written.
4179 *
4180 * @return Status.
4181 *
4182 * @implemented
4183 */
4184 NTSTATUS STDCALL
4185 NtQuerySection(IN HANDLE SectionHandle,
4186 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4187 OUT PVOID SectionInformation,
4188 IN ULONG SectionInformationLength,
4189 OUT PULONG ResultLength OPTIONAL)
4190 {
4191 PROS_SECTION_OBJECT Section;
4192 KPROCESSOR_MODE PreviousMode;
4193 NTSTATUS Status = STATUS_SUCCESS;
4194
4195 PreviousMode = ExGetPreviousMode();
4196
4197 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4198 ExSectionInfoClass,
4199 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4200 SectionInformation,
4201 SectionInformationLength,
4202 ResultLength,
4203 PreviousMode);
4204
4205 if(!NT_SUCCESS(Status))
4206 {
4207 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4208 return Status;
4209 }
4210
4211 Status = ObReferenceObjectByHandle(SectionHandle,
4212 SECTION_QUERY,
4213 MmSectionObjectType,
4214 PreviousMode,
4215 (PVOID*)(PVOID)&Section,
4216 NULL);
4217 if (NT_SUCCESS(Status))
4218 {
4219 switch (SectionInformationClass)
4220 {
4221 case SectionBasicInformation:
4222 {
4223 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4224
4225 _SEH_TRY
4226 {
4227 Sbi->Attributes = Section->AllocationAttributes;
4228 if (Section->AllocationAttributes & SEC_IMAGE)
4229 {
4230 Sbi->BaseAddress = 0;
4231 Sbi->Size.QuadPart = 0;
4232 }
4233 else
4234 {
4235 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4236 Sbi->Size.QuadPart = Section->Segment->Length;
4237 }
4238
4239 if (ResultLength != NULL)
4240 {
4241 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4242 }
4243 Status = STATUS_SUCCESS;
4244 }
4245 _SEH_HANDLE
4246 {
4247 Status = _SEH_GetExceptionCode();
4248 }
4249 _SEH_END;
4250
4251 break;
4252 }
4253
4254 case SectionImageInformation:
4255 {
4256 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4257
4258 _SEH_TRY
4259 {
4260 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4261 if (Section->AllocationAttributes & SEC_IMAGE)
4262 {
4263 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4264 ImageSectionObject = Section->ImageSection;
4265
4266 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4267 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4268 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4269 Sii->SubSystemType = ImageSectionObject->Subsystem;
4270 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4271 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4272 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4273 Sii->Machine = ImageSectionObject->Machine;
4274 Sii->ImageContainsCode = ImageSectionObject->Executable;
4275 }
4276
4277 if (ResultLength != NULL)
4278 {
4279 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4280 }
4281 Status = STATUS_SUCCESS;
4282 }
4283 _SEH_HANDLE
4284 {
4285 Status = _SEH_GetExceptionCode();
4286 }
4287 _SEH_END;
4288
4289 break;
4290 }
4291 }
4292
4293 ObDereferenceObject(Section);
4294 }
4295
4296 return(Status);
4297 }
4298
4299
4300 /**
4301 * Extends size of file backed section.
4302 *
4303 * @param SectionHandle
4304 * Handle to the section object. It must be opened with
4305 * SECTION_EXTEND_SIZE access.
4306 * @param NewMaximumSize
4307 * New maximum size of the section in bytes.
4308 *
4309 * @return Status.
4310 *
4311 * @todo Move the actual code to internal function MmExtendSection.
4312 * @unimplemented
4313 */
4314 NTSTATUS STDCALL
4315 NtExtendSection(IN HANDLE SectionHandle,
4316 IN PLARGE_INTEGER NewMaximumSize)
4317 {
4318 LARGE_INTEGER SafeNewMaximumSize;
4319 PROS_SECTION_OBJECT Section;
4320 KPROCESSOR_MODE PreviousMode;
4321 NTSTATUS Status = STATUS_SUCCESS;
4322
4323 PreviousMode = ExGetPreviousMode();
4324
4325 if(PreviousMode != KernelMode)
4326 {
4327 _SEH_TRY
4328 {
4329 /* make a copy on the stack */
4330 SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
4331 NewMaximumSize = &SafeNewMaximumSize;
4332 }
4333 _SEH_HANDLE
4334 {
4335 Status = _SEH_GetExceptionCode();
4336 }
4337 _SEH_END;
4338
4339 if(!NT_SUCCESS(Status))
4340 {
4341 return Status;
4342 }
4343 }
4344
4345 Status = ObReferenceObjectByHandle(SectionHandle,
4346 SECTION_EXTEND_SIZE,
4347 MmSectionObjectType,
4348 PreviousMode,
4349 (PVOID*)&Section,
4350 NULL);
4351 if (!NT_SUCCESS(Status))
4352 {
4353 return Status;
4354 }
4355
4356 if (!(Section->AllocationAttributes & SEC_FILE))
4357 {
4358 ObfDereferenceObject(Section);
4359 return STATUS_INVALID_PARAMETER;
4360 }
4361
4362 /*
4363 * - Acquire file extneding resource.
4364 * - Check if we're not resizing the section below it's actual size!
4365 * - Extend segments if needed.
4366 * - Set file information (FileAllocationInformation) to the new size.
4367 * - Release file extending resource.
4368 */
4369
4370 ObDereferenceObject(Section);
4371
4372 return STATUS_NOT_IMPLEMENTED;
4373 }
4374
4375
4376 /**********************************************************************
4377 * NAME INTERNAL
4378 * MmAllocateSection@4
4379 *
4380 * DESCRIPTION
4381 *
4382 * ARGUMENTS
4383 * Length
4384 *
4385 * RETURN VALUE
4386 *
4387 * NOTE
4388 * Code taken from ntoskrnl/mm/special.c.
4389 *
4390 * REVISIONS
4391 */
4392 PVOID STDCALL
4393 MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
4394 {
4395 PVOID Result;
4396 MEMORY_AREA* marea;
4397 NTSTATUS Status;
4398 PMM_AVL_TABLE AddressSpace;
4399 PHYSICAL_ADDRESS BoundaryAddressMultiple;
4400
4401 DPRINT("MmAllocateSection(Length %x)\n",Length);
4402
4403 BoundaryAddressMultiple.QuadPart = 0;
4404
4405 AddressSpace = MmGetKernelAddressSpace();
4406 Result = BaseAddress;
4407 MmLockAddressSpace(AddressSpace);
4408 Status = MmCreateMemoryArea (AddressSpace,
4409 MEMORY_AREA_SYSTEM,
4410 &Result,
4411 Length,
4412 0,
4413 &marea,
4414 FALSE,
4415 0,
4416 BoundaryAddressMultiple);
4417 MmUnlockAddressSpace(AddressSpace);
4418
4419 if (!NT_SUCCESS(Status))
4420 {
4421 return (NULL);
4422 }
4423 DPRINT("Result %p\n",Result);
4424
4425 /* Create a virtual mapping for this memory area */
4426 MmMapMemoryArea(Result, Length, MC_NPPOOL, PAGE_READWRITE);
4427
4428 return ((PVOID)Result);
4429 }
4430
4431
4432 /**********************************************************************
4433 * NAME EXPORTED
4434 * MmMapViewOfSection
4435 *
4436 * DESCRIPTION
4437 * Maps a view of a section into the virtual address space of a
4438 * process.
4439 *
4440 * ARGUMENTS
4441 * Section
4442 * Pointer to the section object.
4443 *
4444 * ProcessHandle
4445 * Pointer to the process.
4446 *
4447 * BaseAddress
4448 * Desired base address (or NULL) on entry;
4449 * Actual base address of the view on exit.
4450 *
4451 * ZeroBits
4452 * Number of high order address bits that must be zero.
4453 *
4454 * CommitSize
4455 * Size in bytes of the initially committed section of
4456 * the view.
4457 *
4458 * SectionOffset
4459 * Offset in bytes from the beginning of the section
4460 * to the beginning of the view.
4461 *
4462 * ViewSize
4463 * Desired length of map (or zero to map all) on entry
4464 * Actual length mapped on exit.
4465 *
4466 * InheritDisposition
4467 * Specified how the view is to be shared with
4468 * child processes.
4469 *
4470 * AllocationType
4471 * Type of allocation for the pages.
4472 *
4473 * Protect
4474 * Protection for the committed region of the view.
4475 *
4476 * RETURN VALUE
4477 * Status.
4478 *
4479 * @implemented
4480 */
4481 NTSTATUS STDCALL
4482 MmMapViewOfSection(IN PVOID SectionObject,
4483 IN PEPROCESS Process,
4484 IN OUT PVOID *BaseAddress,
4485 IN ULONG ZeroBits,
4486 IN ULONG CommitSize,
4487 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4488 IN OUT PSIZE_T ViewSize,
4489 IN SECTION_INHERIT InheritDisposition,
4490 IN ULONG AllocationType,
4491 IN ULONG Protect)
4492 {
4493 PROS_SECTION_OBJECT Section;
4494 PMM_AVL_TABLE AddressSpace;
4495 ULONG ViewOffset;
4496 NTSTATUS Status = STATUS_SUCCESS;
4497
4498 ASSERT(Process);
4499
4500 if (Protect != PAGE_READONLY &&
4501 Protect != PAGE_READWRITE &&
4502 Protect != PAGE_WRITECOPY &&
4503 Protect != PAGE_EXECUTE &&
4504 Protect != PAGE_EXECUTE_READ &&
4505 Protect != PAGE_EXECUTE_READWRITE &&
4506 Protect != PAGE_EXECUTE_WRITECOPY)
4507 {
4508 return STATUS_INVALID_PAGE_PROTECTION;
4509 }
4510
4511
4512 Section = (PROS_SECTION_OBJECT)SectionObject;
4513 AddressSpace = &Process->VadRoot;
4514
4515 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4516
4517 MmLockAddressSpace(AddressSpace);
4518
4519 if (Section->AllocationAttributes & SEC_IMAGE)
4520 {
4521 ULONG i;
4522 ULONG NrSegments;
4523 ULONG_PTR ImageBase;
4524 ULONG ImageSize;
4525 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4526 PMM_SECTION_SEGMENT SectionSegments;
4527
4528 ImageSectionObject = Section->ImageSection;
4529 SectionSegments = ImageSectionObject->Segments;
4530 NrSegments = ImageSectionObject->NrSegments;
4531
4532
4533 ImageBase = (ULONG_PTR)*BaseAddress;
4534 if (ImageBase == 0)
4535 {
4536 ImageBase = ImageSectionObject->ImageBase;
4537 }
4538
4539 ImageSize = 0;
4540 for (i = 0; i < NrSegments; i++)
4541 {
4542 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4543 {
4544 ULONG_PTR MaxExtent;
4545 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4546 SectionSegments[i].Length;
4547 ImageSize = max(ImageSize, MaxExtent);
4548 }
4549 }
4550
4551 ImageSectionObject->ImageSize = ImageSize;
4552
4553 /* Check there is enough space to map the section at that point. */
4554 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4555 PAGE_ROUND_UP(ImageSize)) != NULL)
4556 {
4557 /* Fail if the user requested a fixed base address. */
4558 if ((*BaseAddress) != NULL)
4559 {
4560 MmUnlockAddressSpace(AddressSpace);
4561 return(STATUS_UNSUCCESSFUL);
4562 }
4563 /* Otherwise find a gap to map the image. */
4564 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4565 if (ImageBase == 0)
4566 {
4567 MmUnlockAddressSpace(AddressSpace);
4568 return(STATUS_UNSUCCESSFUL);
4569 }
4570 }
4571
4572 for (i = 0; i < NrSegments; i++)
4573 {
4574 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4575 {
4576 PVOID SBaseAddress = (PVOID)
4577 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4578 MmLockSectionSegment(&SectionSegments[i]);
4579 Status = MmMapViewOfSegment(AddressSpace,
4580 Section,
4581 &SectionSegments[i],
4582 &SBaseAddress,
4583 SectionSegments[i].Length,
4584 SectionSegments[i].Protection,
4585 0,
4586 0);
4587 MmUnlockSectionSegment(&SectionSegments[i]);
4588 if (!NT_SUCCESS(Status))
4589 {
4590 MmUnlockAddressSpace(AddressSpace);
4591 return(Status);
4592 }
4593 }
4594 }
4595
4596 *BaseAddress = (PVOID)ImageBase;
4597 }
4598 else
4599 {
4600 /* check for write access */
4601 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4602 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4603 {
4604 return STATUS_SECTION_PROTECTION;
4605 }
4606 /* check for read access */
4607 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4608 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4609 {
4610 return STATUS_SECTION_PROTECTION;
4611 }
4612 /* check for execute access */
4613 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4614 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4615 {
4616 return STATUS_SECTION_PROTECTION;
4617 }
4618
4619 if (ViewSize == NULL)
4620 {
4621 /* Following this pointer would lead to us to the dark side */
4622 /* What to do? Bugcheck? Return status? Do the mambo? */
4623 KeBugCheck(MEMORY_MANAGEMENT);
4624 }
4625
4626 if (SectionOffset == NULL)
4627 {
4628 ViewOffset = 0;
4629 }
4630 else
4631 {
4632 ViewOffset = SectionOffset->u.LowPart;
4633 }
4634
4635 if ((ViewOffset % PAGE_SIZE) != 0)
4636 {
4637 MmUnlockAddressSpace(AddressSpace);
4638 return(STATUS_MAPPED_ALIGNMENT);
4639 }
4640
4641 if ((*ViewSize) == 0)
4642 {
4643 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4644 }
4645 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4646 {
4647 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4648 }
4649
4650 MmLockSectionSegment(Section->Segment);
4651 Status = MmMapViewOfSegment(AddressSpace,
4652 Section,
4653 Section->Segment,
4654 BaseAddress,
4655 *ViewSize,
4656 Protect,
4657 ViewOffset,
4658 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4659 MmUnlockSectionSegment(Section->Segment);
4660 if (!NT_SUCCESS(Status))
4661 {
4662 MmUnlockAddressSpace(AddressSpace);
4663 return(Status);
4664 }
4665 }
4666
4667 MmUnlockAddressSpace(AddressSpace);
4668
4669 return(STATUS_SUCCESS);
4670 }
4671
4672 /*
4673 * @unimplemented
4674 */
4675 BOOLEAN STDCALL
4676 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4677 IN PLARGE_INTEGER NewFileSize)
4678 {
4679 UNIMPLEMENTED;
4680 return (FALSE);
4681 }
4682
4683
4684 /*
4685 * @unimplemented
4686 */
4687 BOOLEAN STDCALL
4688 MmDisableModifiedWriteOfSection (ULONG Unknown0)
4689 {
4690 UNIMPLEMENTED;
4691 return (FALSE);
4692 }
4693
4694 /*
4695 * @implemented
4696 */
4697 BOOLEAN STDCALL
4698 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4699 IN MMFLUSH_TYPE FlushType)
4700 {
4701 switch(FlushType)
4702 {
4703 case MmFlushForDelete:
4704 if (SectionObjectPointer->ImageSectionObject ||
4705 SectionObjectPointer->DataSectionObject)
4706 {
4707 return FALSE;
4708 }
4709 CcRosSetRemoveOnClose(SectionObjectPointer);
4710 return TRUE;
4711 case MmFlushForWrite:
4712 break;
4713 }
4714 return FALSE;
4715 }
4716
4717 /*
4718 * @unimplemented
4719 */
4720 BOOLEAN STDCALL
4721 MmForceSectionClosed (
4722 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4723 IN BOOLEAN DelayClose)
4724 {
4725 UNIMPLEMENTED;
4726 return (FALSE);
4727 }
4728
4729
4730 /*
4731 * @implemented
4732 */
4733 NTSTATUS STDCALL
4734 MmMapViewInSystemSpace (IN PVOID SectionObject,
4735 OUT PVOID * MappedBase,
4736 IN OUT PULONG ViewSize)
4737 {
4738 PROS_SECTION_OBJECT Section;
4739 PMM_AVL_TABLE AddressSpace;
4740 NTSTATUS Status;
4741
4742 DPRINT("MmMapViewInSystemSpace() called\n");
4743
4744 Section = (PROS_SECTION_OBJECT)SectionObject;
4745 AddressSpace = MmGetKernelAddressSpace();
4746
4747 MmLockAddressSpace(AddressSpace);
4748
4749
4750 if ((*ViewSize) == 0)
4751 {
4752 (*ViewSize) = Section->MaximumSize.u.LowPart;
4753 }
4754 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4755 {
4756 (*ViewSize) = Section->MaximumSize.u.LowPart;
4757 }
4758
4759 MmLockSectionSegment(Section->Segment);
4760
4761
4762 Status = MmMapViewOfSegment(AddressSpace,
4763 Section,
4764 Section->Segment,
4765 MappedBase,
4766 *ViewSize,
4767 PAGE_READWRITE,
4768 0,
4769 0);
4770
4771 MmUnlockSectionSegment(Section->Segment);
4772 MmUnlockAddressSpace(AddressSpace);
4773
4774 return Status;
4775 }
4776
4777 /*
4778 * @unimplemented
4779 */
4780 NTSTATUS
4781 STDCALL
4782 MmMapViewInSessionSpace (
4783 IN PVOID Section,
4784 OUT PVOID *MappedBase,
4785 IN OUT PSIZE_T ViewSize
4786 )
4787 {
4788 UNIMPLEMENTED;
4789 return STATUS_NOT_IMPLEMENTED;
4790 }
4791
4792
4793 /*
4794 * @implemented
4795 */
4796 NTSTATUS STDCALL
4797 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4798 {
4799 PMM_AVL_TABLE AddressSpace;
4800 NTSTATUS Status;
4801
4802 DPRINT("MmUnmapViewInSystemSpace() called\n");
4803
4804 AddressSpace = MmGetKernelAddressSpace();
4805
4806 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4807
4808 return Status;
4809 }
4810
4811 /*
4812 * @unimplemented
4813 */
4814 NTSTATUS
4815 STDCALL
4816 MmUnmapViewInSessionSpace (
4817 IN PVOID MappedBase
4818 )
4819 {
4820 UNIMPLEMENTED;
4821 return STATUS_NOT_IMPLEMENTED;
4822 }
4823
4824 /*
4825 * @unimplemented
4826 */
4827 NTSTATUS STDCALL
4828 MmSetBankedSection (ULONG Unknown0,
4829 ULONG Unknown1,
4830 ULONG Unknown2,
4831 ULONG Unknown3,
4832 ULONG Unknown4,
4833 ULONG Unknown5)
4834 {
4835 UNIMPLEMENTED;
4836 return (STATUS_NOT_IMPLEMENTED);
4837 }
4838
4839
4840 /**********************************************************************
4841 * NAME EXPORTED
4842 * MmCreateSection@
4843 *
4844 * DESCRIPTION
4845 * Creates a section object.
4846 *
4847 * ARGUMENTS
4848 * SectionObject (OUT)
4849 * Caller supplied storage for the resulting pointer
4850 * to a SECTION_OBJECT instance;
4851 *
4852 * DesiredAccess
4853 * Specifies the desired access to the section can be a
4854 * combination of:
4855 * STANDARD_RIGHTS_REQUIRED |
4856 * SECTION_QUERY |
4857 * SECTION_MAP_WRITE |
4858 * SECTION_MAP_READ |
4859 * SECTION_MAP_EXECUTE
4860 *
4861 * ObjectAttributes [OPTIONAL]
4862 * Initialized attributes for the object can be used
4863 * to create a named section;
4864 *
4865 * MaximumSize
4866 * Maximizes the size of the memory section. Must be
4867 * non-NULL for a page-file backed section.
4868 * If value specified for a mapped file and the file is
4869 * not large enough, file will be extended.
4870 *
4871 * SectionPageProtection
4872 * Can be a combination of:
4873 * PAGE_READONLY |
4874 * PAGE_READWRITE |
4875 * PAGE_WRITEONLY |
4876 * PAGE_WRITECOPY
4877 *
4878 * AllocationAttributes
4879 * Can be a combination of:
4880 * SEC_IMAGE |
4881 * SEC_RESERVE
4882 *
4883 * FileHandle
4884 * Handle to a file to create a section mapped to a file
4885 * instead of a memory backed section;
4886 *
4887 * File
4888 * Unknown.
4889 *
4890 * RETURN VALUE
4891 * Status.
4892 *
4893 * @implemented
4894 */
4895 NTSTATUS STDCALL
4896 MmCreateSection (OUT PVOID * Section,
4897 IN ACCESS_MASK DesiredAccess,
4898 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4899 IN PLARGE_INTEGER MaximumSize,
4900 IN ULONG SectionPageProtection,
4901 IN ULONG AllocationAttributes,
4902 IN HANDLE FileHandle OPTIONAL,
4903 IN PFILE_OBJECT File OPTIONAL)
4904 {
4905 ULONG Protection;
4906 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4907
4908 /*
4909 * Check the protection
4910 */
4911 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
4912 if (Protection != PAGE_NOACCESS &&
4913 Protection != PAGE_READONLY &&
4914 Protection != PAGE_READWRITE &&
4915 Protection != PAGE_WRITECOPY &&
4916 Protection != PAGE_EXECUTE &&
4917 Protection != PAGE_EXECUTE_READ &&
4918 Protection != PAGE_EXECUTE_READWRITE &&
4919 Protection != PAGE_EXECUTE_WRITECOPY)
4920 {
4921 return STATUS_INVALID_PAGE_PROTECTION;
4922 }
4923
4924 if (AllocationAttributes & SEC_IMAGE)
4925 {
4926 return(MmCreateImageSection(SectionObject,
4927 DesiredAccess,
4928 ObjectAttributes,
4929 MaximumSize,
4930 SectionPageProtection,
4931 AllocationAttributes,
4932 FileHandle));
4933 }
4934
4935 if (FileHandle != NULL)
4936 {
4937 return(MmCreateDataFileSection(SectionObject,
4938 DesiredAccess,
4939 ObjectAttributes,
4940 MaximumSize,
4941 SectionPageProtection,
4942 AllocationAttributes,
4943 FileHandle));
4944 }
4945
4946 return(MmCreatePageFileSection(SectionObject,
4947 DesiredAccess,
4948 ObjectAttributes,
4949 MaximumSize,
4950 SectionPageProtection,
4951 AllocationAttributes));
4952 }
4953
4954 NTSTATUS
4955 NTAPI
4956 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
4957 IN OUT PULONG NumberOfPages,
4958 IN OUT PULONG UserPfnArray)
4959 {
4960 UNIMPLEMENTED;
4961 return STATUS_NOT_IMPLEMENTED;
4962 }
4963
4964 NTSTATUS
4965 NTAPI
4966 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
4967 IN ULONG NumberOfPages,
4968 IN OUT PULONG UserPfnArray)
4969 {
4970 UNIMPLEMENTED;
4971 return STATUS_NOT_IMPLEMENTED;
4972 }
4973
4974 NTSTATUS
4975 NTAPI
4976 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
4977 IN ULONG NumberOfPages,
4978 IN OUT PULONG UserPfnArray)
4979 {
4980 UNIMPLEMENTED;
4981 return STATUS_NOT_IMPLEMENTED;
4982 }
4983
4984 NTSTATUS
4985 NTAPI
4986 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
4987 IN OUT PULONG NumberOfPages,
4988 IN OUT PULONG UserPfnArray)
4989 {
4990 UNIMPLEMENTED;
4991 return STATUS_NOT_IMPLEMENTED;
4992 }
4993
4994 NTSTATUS
4995 NTAPI
4996 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
4997 IN PVOID File2MappedAsFile)
4998 {
4999 UNIMPLEMENTED;
5000 return STATUS_NOT_IMPLEMENTED;
5001 }
5002
5003
5004 /* EOF */