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