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