- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[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 Status = ObReferenceObjectByHandle(ProcessHandle,
3743 PROCESS_VM_OPERATION,
3744 PsProcessType,
3745 PreviousMode,
3746 (PVOID*)(PVOID)&Process,
3747 NULL);
3748 if (!NT_SUCCESS(Status))
3749 {
3750 return(Status);
3751 }
3752
3753 AddressSpace = (PMADDRESS_SPACE)&Process->VadRoot;
3754
3755 Status = ObReferenceObjectByHandle(SectionHandle,
3756 SECTION_MAP_READ,
3757 MmSectionObjectType,
3758 PreviousMode,
3759 (PVOID*)(PVOID)&Section,
3760 NULL);
3761 if (!(NT_SUCCESS(Status)))
3762 {
3763 DPRINT("ObReference failed rc=%x\n",Status);
3764 ObDereferenceObject(Process);
3765 return(Status);
3766 }
3767
3768 Status = MmMapViewOfSection(Section,
3769 (PEPROCESS)Process,
3770 (BaseAddress != NULL ? &SafeBaseAddress : NULL),
3771 ZeroBits,
3772 CommitSize,
3773 (SectionOffset != NULL ? &SafeSectionOffset : NULL),
3774 (ViewSize != NULL ? &SafeViewSize : NULL),
3775 InheritDisposition,
3776 AllocationType,
3777 Protect);
3778
3779 /* Check if this is an image for the current process */
3780 if ((Section->AllocationAttributes & SEC_IMAGE) &&
3781 (Process == PsGetCurrentProcess()) &&
3782 (Status != STATUS_IMAGE_NOT_AT_BASE))
3783 {
3784 /* Notify the debugger */
3785 DbgkMapViewOfSection(Section,
3786 SafeBaseAddress,
3787 SafeSectionOffset.LowPart,
3788 SafeViewSize);
3789 }
3790
3791 ObDereferenceObject(Section);
3792 ObDereferenceObject(Process);
3793
3794 if(NT_SUCCESS(Status))
3795 {
3796 /* copy parameters back to the caller */
3797 _SEH_TRY
3798 {
3799 if(BaseAddress != NULL)
3800 {
3801 *BaseAddress = SafeBaseAddress;
3802 }
3803 if(SectionOffset != NULL)
3804 {
3805 *SectionOffset = SafeSectionOffset;
3806 }
3807 if(ViewSize != NULL)
3808 {
3809 *ViewSize = SafeViewSize;
3810 }
3811 }
3812 _SEH_HANDLE
3813 {
3814 Status = _SEH_GetExceptionCode();
3815 }
3816 _SEH_END;
3817 }
3818
3819 return(Status);
3820 }
3821
3822 VOID static
3823 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3824 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3825 {
3826 ULONG Entry;
3827 PFILE_OBJECT FileObject;
3828 PBCB Bcb;
3829 ULONG Offset;
3830 SWAPENTRY SavedSwapEntry;
3831 PMM_PAGEOP PageOp;
3832 NTSTATUS Status;
3833 PROS_SECTION_OBJECT Section;
3834 PMM_SECTION_SEGMENT Segment;
3835 PMADDRESS_SPACE AddressSpace;
3836
3837 AddressSpace = (PMADDRESS_SPACE)Context;
3838
3839 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3840
3841 Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
3842 MemoryArea->Data.SectionData.ViewOffset;
3843
3844 Section = MemoryArea->Data.SectionData.Section;
3845 Segment = MemoryArea->Data.SectionData.Segment;
3846
3847 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3848
3849 while (PageOp)
3850 {
3851 MmUnlockSectionSegment(Segment);
3852 MmUnlockAddressSpace(AddressSpace);
3853
3854 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3855 if (Status != STATUS_SUCCESS)
3856 {
3857 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3858 KEBUGCHECK(0);
3859 }
3860
3861 MmLockAddressSpace(AddressSpace);
3862 MmLockSectionSegment(Segment);
3863 MmspCompleteAndReleasePageOp(PageOp);
3864 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3865 }
3866
3867 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3868
3869 /*
3870 * For a dirty, datafile, non-private page mark it as dirty in the
3871 * cache manager.
3872 */
3873 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3874 {
3875 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3876 {
3877 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3878 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3879 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
3880 ASSERT(SwapEntry == 0);
3881 }
3882 }
3883
3884 if (SwapEntry != 0)
3885 {
3886 /*
3887 * Sanity check
3888 */
3889 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3890 {
3891 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3892 KEBUGCHECK(0);
3893 }
3894 MmFreeSwapPage(SwapEntry);
3895 }
3896 else if (Page != 0)
3897 {
3898 if (IS_SWAP_FROM_SSE(Entry) ||
3899 Page != PFN_FROM_SSE(Entry))
3900 {
3901 /*
3902 * Sanity check
3903 */
3904 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3905 {
3906 DPRINT1("Found a private page in a pagefile section.\n");
3907 KEBUGCHECK(0);
3908 }
3909 /*
3910 * Just dereference private pages
3911 */
3912 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3913 if (SavedSwapEntry != 0)
3914 {
3915 MmFreeSwapPage(SavedSwapEntry);
3916 MmSetSavedSwapEntryPage(Page, 0);
3917 }
3918 MmDeleteRmap(Page, AddressSpace->Process, Address);
3919 MmReleasePageMemoryConsumer(MC_USER, Page);
3920 }
3921 else
3922 {
3923 MmDeleteRmap(Page, AddressSpace->Process, Address);
3924 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3925 }
3926 }
3927 }
3928
3929 static NTSTATUS
3930 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3931 PVOID BaseAddress)
3932 {
3933 NTSTATUS Status;
3934 PMEMORY_AREA MemoryArea;
3935 PROS_SECTION_OBJECT Section;
3936 PMM_SECTION_SEGMENT Segment;
3937 PLIST_ENTRY CurrentEntry;
3938 PMM_REGION CurrentRegion;
3939 PLIST_ENTRY RegionListHead;
3940
3941 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3942 BaseAddress);
3943 if (MemoryArea == NULL)
3944 {
3945 return(STATUS_UNSUCCESSFUL);
3946 }
3947
3948 MemoryArea->DeleteInProgress = TRUE;
3949 Section = MemoryArea->Data.SectionData.Section;
3950 Segment = MemoryArea->Data.SectionData.Segment;
3951
3952 MmLockSectionSegment(Segment);
3953
3954 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3955 while (!IsListEmpty(RegionListHead))
3956 {
3957 CurrentEntry = RemoveHeadList(RegionListHead);
3958 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3959 ExFreePool(CurrentRegion);
3960 }
3961
3962 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3963 {
3964 Status = MmFreeMemoryArea(AddressSpace,
3965 MemoryArea,
3966 NULL,
3967 NULL);
3968 }
3969 else
3970 {
3971 Status = MmFreeMemoryArea(AddressSpace,
3972 MemoryArea,
3973 MmFreeSectionPage,
3974 AddressSpace);
3975 }
3976 MmUnlockSectionSegment(Segment);
3977 ObDereferenceObject(Section);
3978 return(STATUS_SUCCESS);
3979 }
3980
3981 /*
3982 * @implemented
3983 */
3984 NTSTATUS STDCALL
3985 MmUnmapViewOfSection(PEPROCESS Process,
3986 PVOID BaseAddress)
3987 {
3988 NTSTATUS Status;
3989 PMEMORY_AREA MemoryArea;
3990 PMADDRESS_SPACE AddressSpace;
3991 PROS_SECTION_OBJECT Section;
3992 PMM_PAGEOP PageOp;
3993 ULONG_PTR Offset;
3994 PVOID ImageBaseAddress = 0;
3995
3996 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3997 Process, BaseAddress);
3998
3999 ASSERT(Process);
4000
4001 AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot;
4002
4003 MmLockAddressSpace(AddressSpace);
4004 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4005 BaseAddress);
4006 if (MemoryArea == NULL ||
4007 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4008 MemoryArea->DeleteInProgress)
4009 {
4010 MmUnlockAddressSpace(AddressSpace);
4011 return STATUS_NOT_MAPPED_VIEW;
4012 }
4013
4014 MemoryArea->DeleteInProgress = TRUE;
4015
4016 while (MemoryArea->PageOpCount)
4017 {
4018 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4019
4020 while (Offset)
4021 {
4022 Offset -= PAGE_SIZE;
4023 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4024 MemoryArea->Data.SectionData.Segment,
4025 Offset + MemoryArea->Data.SectionData.ViewOffset);
4026 if (PageOp)
4027 {
4028 MmUnlockAddressSpace(AddressSpace);
4029 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4030 if (Status != STATUS_SUCCESS)
4031 {
4032 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4033 KEBUGCHECK(0);
4034 }
4035 MmLockAddressSpace(AddressSpace);
4036 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4037 BaseAddress);
4038 if (MemoryArea == NULL ||
4039 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4040 {
4041 MmUnlockAddressSpace(AddressSpace);
4042 return STATUS_NOT_MAPPED_VIEW;
4043 }
4044 break;
4045 }
4046 }
4047 }
4048
4049 Section = MemoryArea->Data.SectionData.Section;
4050
4051 if (Section->AllocationAttributes & SEC_IMAGE)
4052 {
4053 ULONG i;
4054 ULONG NrSegments;
4055 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4056 PMM_SECTION_SEGMENT SectionSegments;
4057 PMM_SECTION_SEGMENT Segment;
4058
4059 Segment = MemoryArea->Data.SectionData.Segment;
4060 ImageSectionObject = Section->ImageSection;
4061 SectionSegments = ImageSectionObject->Segments;
4062 NrSegments = ImageSectionObject->NrSegments;
4063
4064 /* Search for the current segment within the section segments
4065 * and calculate the image base address */
4066 for (i = 0; i < NrSegments; i++)
4067 {
4068 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4069 {
4070 if (Segment == &SectionSegments[i])
4071 {
4072 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
4073 break;
4074 }
4075 }
4076 }
4077 if (i >= NrSegments)
4078 {
4079 KEBUGCHECK(0);
4080 }
4081
4082 for (i = 0; i < NrSegments; i++)
4083 {
4084 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4085 {
4086 PVOID SBaseAddress = (PVOID)
4087 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4088
4089 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4090 }
4091 }
4092 }
4093 else
4094 {
4095 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4096 }
4097
4098 /* Notify debugger */
4099 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4100
4101 MmUnlockAddressSpace(AddressSpace);
4102 return(STATUS_SUCCESS);
4103 }
4104
4105 /**********************************************************************
4106 * NAME EXPORTED
4107 * NtUnmapViewOfSection
4108 *
4109 * DESCRIPTION
4110 *
4111 * ARGUMENTS
4112 * ProcessHandle
4113 *
4114 * BaseAddress
4115 *
4116 * RETURN VALUE
4117 * Status.
4118 *
4119 * REVISIONS
4120 */
4121 NTSTATUS STDCALL
4122 NtUnmapViewOfSection (HANDLE ProcessHandle,
4123 PVOID BaseAddress)
4124 {
4125 PEPROCESS Process;
4126 KPROCESSOR_MODE PreviousMode;
4127 NTSTATUS Status;
4128
4129 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4130 ProcessHandle, BaseAddress);
4131
4132 PreviousMode = ExGetPreviousMode();
4133
4134 DPRINT("Referencing process\n");
4135 Status = ObReferenceObjectByHandle(ProcessHandle,
4136 PROCESS_VM_OPERATION,
4137 PsProcessType,
4138 PreviousMode,
4139 (PVOID*)(PVOID)&Process,
4140 NULL);
4141 if (!NT_SUCCESS(Status))
4142 {
4143 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
4144 return(Status);
4145 }
4146
4147 Status = MmUnmapViewOfSection(Process, BaseAddress);
4148
4149 ObDereferenceObject(Process);
4150
4151 return Status;
4152 }
4153
4154
4155 /**
4156 * Queries the information of a section object.
4157 *
4158 * @param SectionHandle
4159 * Handle to the section object. It must be opened with SECTION_QUERY
4160 * access.
4161 * @param SectionInformationClass
4162 * Index to a certain information structure. Can be either
4163 * SectionBasicInformation or SectionImageInformation. The latter
4164 * is valid only for sections that were created with the SEC_IMAGE
4165 * flag.
4166 * @param SectionInformation
4167 * Caller supplies storage for resulting information.
4168 * @param Length
4169 * Size of the supplied storage.
4170 * @param ResultLength
4171 * Data written.
4172 *
4173 * @return Status.
4174 *
4175 * @implemented
4176 */
4177 NTSTATUS STDCALL
4178 NtQuerySection(IN HANDLE SectionHandle,
4179 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4180 OUT PVOID SectionInformation,
4181 IN ULONG SectionInformationLength,
4182 OUT PULONG ResultLength OPTIONAL)
4183 {
4184 PROS_SECTION_OBJECT Section;
4185 KPROCESSOR_MODE PreviousMode;
4186 NTSTATUS Status = STATUS_SUCCESS;
4187
4188 PreviousMode = ExGetPreviousMode();
4189
4190 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4191 ExSectionInfoClass,
4192 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4193 SectionInformation,
4194 SectionInformationLength,
4195 ResultLength,
4196 PreviousMode);
4197
4198 if(!NT_SUCCESS(Status))
4199 {
4200 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4201 return Status;
4202 }
4203
4204 Status = ObReferenceObjectByHandle(SectionHandle,
4205 SECTION_QUERY,
4206 MmSectionObjectType,
4207 PreviousMode,
4208 (PVOID*)(PVOID)&Section,
4209 NULL);
4210 if (NT_SUCCESS(Status))
4211 {
4212 switch (SectionInformationClass)
4213 {
4214 case SectionBasicInformation:
4215 {
4216 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4217
4218 _SEH_TRY
4219 {
4220 Sbi->Attributes = Section->AllocationAttributes;
4221 if (Section->AllocationAttributes & SEC_IMAGE)
4222 {
4223 Sbi->BaseAddress = 0;
4224 Sbi->Size.QuadPart = 0;
4225 }
4226 else
4227 {
4228 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4229 Sbi->Size.QuadPart = Section->Segment->Length;
4230 }
4231
4232 if (ResultLength != NULL)
4233 {
4234 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4235 }
4236 Status = STATUS_SUCCESS;
4237 }
4238 _SEH_HANDLE
4239 {
4240 Status = _SEH_GetExceptionCode();
4241 }
4242 _SEH_END;
4243
4244 break;
4245 }
4246
4247 case SectionImageInformation:
4248 {
4249 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4250
4251 _SEH_TRY
4252 {
4253 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4254 if (Section->AllocationAttributes & SEC_IMAGE)
4255 {
4256 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4257 ImageSectionObject = Section->ImageSection;
4258
4259 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4260 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4261 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4262 Sii->SubsystemType = ImageSectionObject->Subsystem;
4263 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4264 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4265 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4266 Sii->Machine = ImageSectionObject->Machine;
4267 Sii->ImageContainsCode = ImageSectionObject->Executable;
4268 }
4269
4270 if (ResultLength != NULL)
4271 {
4272 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4273 }
4274 Status = STATUS_SUCCESS;
4275 }
4276 _SEH_HANDLE
4277 {
4278 Status = _SEH_GetExceptionCode();
4279 }
4280 _SEH_END;
4281
4282 break;
4283 }
4284 }
4285
4286 ObDereferenceObject(Section);
4287 }
4288
4289 return(Status);
4290 }
4291
4292
4293 /**
4294 * Extends size of file backed section.
4295 *
4296 * @param SectionHandle
4297 * Handle to the section object. It must be opened with
4298 * SECTION_EXTEND_SIZE access.
4299 * @param NewMaximumSize
4300 * New maximum size of the section in bytes.
4301 *
4302 * @return Status.
4303 *
4304 * @todo Move the actual code to internal function MmExtendSection.
4305 * @unimplemented
4306 */
4307 NTSTATUS STDCALL
4308 NtExtendSection(IN HANDLE SectionHandle,
4309 IN PLARGE_INTEGER NewMaximumSize)
4310 {
4311 LARGE_INTEGER SafeNewMaximumSize;
4312 PROS_SECTION_OBJECT Section;
4313 KPROCESSOR_MODE PreviousMode;
4314 NTSTATUS Status = STATUS_SUCCESS;
4315
4316 PreviousMode = ExGetPreviousMode();
4317
4318 if(PreviousMode != KernelMode)
4319 {
4320 _SEH_TRY
4321 {
4322 /* make a copy on the stack */
4323 SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
4324 NewMaximumSize = &SafeNewMaximumSize;
4325 }
4326 _SEH_HANDLE
4327 {
4328 Status = _SEH_GetExceptionCode();
4329 }
4330 _SEH_END;
4331
4332 if(!NT_SUCCESS(Status))
4333 {
4334 return Status;
4335 }
4336 }
4337
4338 Status = ObReferenceObjectByHandle(SectionHandle,
4339 SECTION_EXTEND_SIZE,
4340 MmSectionObjectType,
4341 PreviousMode,
4342 (PVOID*)&Section,
4343 NULL);
4344 if (!NT_SUCCESS(Status))
4345 {
4346 return Status;
4347 }
4348
4349 if (!(Section->AllocationAttributes & SEC_FILE))
4350 {
4351 ObfDereferenceObject(Section);
4352 return STATUS_INVALID_PARAMETER;
4353 }
4354
4355 /*
4356 * - Acquire file extneding resource.
4357 * - Check if we're not resizing the section below it's actual size!
4358 * - Extend segments if needed.
4359 * - Set file information (FileAllocationInformation) to the new size.
4360 * - Release file extending resource.
4361 */
4362
4363 ObDereferenceObject(Section);
4364
4365 return STATUS_NOT_IMPLEMENTED;
4366 }
4367
4368
4369 /**********************************************************************
4370 * NAME INTERNAL
4371 * MmAllocateSection@4
4372 *
4373 * DESCRIPTION
4374 *
4375 * ARGUMENTS
4376 * Length
4377 *
4378 * RETURN VALUE
4379 *
4380 * NOTE
4381 * Code taken from ntoskrnl/mm/special.c.
4382 *
4383 * REVISIONS
4384 */
4385 PVOID STDCALL
4386 MmAllocateSection (IN ULONG Length, PVOID BaseAddress)
4387 {
4388 PVOID Result;
4389 MEMORY_AREA* marea;
4390 NTSTATUS Status;
4391 ULONG i;
4392 PMADDRESS_SPACE AddressSpace;
4393 PHYSICAL_ADDRESS BoundaryAddressMultiple;
4394
4395 DPRINT("MmAllocateSection(Length %x)\n",Length);
4396
4397 BoundaryAddressMultiple.QuadPart = 0;
4398
4399 AddressSpace = MmGetKernelAddressSpace();
4400 Result = BaseAddress;
4401 MmLockAddressSpace(AddressSpace);
4402 Status = MmCreateMemoryArea (AddressSpace,
4403 MEMORY_AREA_SYSTEM,
4404 &Result,
4405 Length,
4406 0,
4407 &marea,
4408 FALSE,
4409 0,
4410 BoundaryAddressMultiple);
4411 MmUnlockAddressSpace(AddressSpace);
4412
4413 if (!NT_SUCCESS(Status))
4414 {
4415 return (NULL);
4416 }
4417 DPRINT("Result %p\n",Result);
4418 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
4419 {
4420 PFN_TYPE Page;
4421
4422 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
4423 if (!NT_SUCCESS(Status))
4424 {
4425 DPRINT1("Unable to allocate page\n");
4426 KEBUGCHECK(0);
4427 }
4428 Status = MmCreateVirtualMapping (NULL,
4429 (PVOID)((ULONG_PTR)Result + (i * PAGE_SIZE)),
4430 PAGE_READWRITE,
4431 &Page,
4432 1);
4433 if (!NT_SUCCESS(Status))
4434 {
4435 DPRINT1("Unable to create virtual mapping\n");
4436 KEBUGCHECK(0);
4437 }
4438 }
4439 return ((PVOID)Result);
4440 }
4441
4442
4443 /**********************************************************************
4444 * NAME EXPORTED
4445 * MmMapViewOfSection
4446 *
4447 * DESCRIPTION
4448 * Maps a view of a section into the virtual address space of a
4449 * process.
4450 *
4451 * ARGUMENTS
4452 * Section
4453 * Pointer to the section object.
4454 *
4455 * ProcessHandle
4456 * Pointer to the process.
4457 *
4458 * BaseAddress
4459 * Desired base address (or NULL) on entry;
4460 * Actual base address of the view on exit.
4461 *
4462 * ZeroBits
4463 * Number of high order address bits that must be zero.
4464 *
4465 * CommitSize
4466 * Size in bytes of the initially committed section of
4467 * the view.
4468 *
4469 * SectionOffset
4470 * Offset in bytes from the beginning of the section
4471 * to the beginning of the view.
4472 *
4473 * ViewSize
4474 * Desired length of map (or zero to map all) on entry
4475 * Actual length mapped on exit.
4476 *
4477 * InheritDisposition
4478 * Specified how the view is to be shared with
4479 * child processes.
4480 *
4481 * AllocationType
4482 * Type of allocation for the pages.
4483 *
4484 * Protect
4485 * Protection for the committed region of the view.
4486 *
4487 * RETURN VALUE
4488 * Status.
4489 *
4490 * @implemented
4491 */
4492 NTSTATUS STDCALL
4493 MmMapViewOfSection(IN PVOID SectionObject,
4494 IN PEPROCESS Process,
4495 IN OUT PVOID *BaseAddress,
4496 IN ULONG ZeroBits,
4497 IN ULONG CommitSize,
4498 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4499 IN OUT PSIZE_T ViewSize,
4500 IN SECTION_INHERIT InheritDisposition,
4501 IN ULONG AllocationType,
4502 IN ULONG Protect)
4503 {
4504 PROS_SECTION_OBJECT Section;
4505 PMADDRESS_SPACE AddressSpace;
4506 ULONG ViewOffset;
4507 NTSTATUS Status = STATUS_SUCCESS;
4508
4509 ASSERT(Process);
4510
4511 if (Protect != PAGE_READONLY &&
4512 Protect != PAGE_READWRITE &&
4513 Protect != PAGE_WRITECOPY &&
4514 Protect != PAGE_EXECUTE &&
4515 Protect != PAGE_EXECUTE_READ &&
4516 Protect != PAGE_EXECUTE_READWRITE &&
4517 Protect != PAGE_EXECUTE_WRITECOPY)
4518 {
4519 CHECKPOINT1;
4520 return STATUS_INVALID_PAGE_PROTECTION;
4521 }
4522
4523
4524 Section = (PROS_SECTION_OBJECT)SectionObject;
4525 AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot;
4526
4527 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4528
4529 MmLockAddressSpace(AddressSpace);
4530
4531 if (Section->AllocationAttributes & SEC_IMAGE)
4532 {
4533 ULONG i;
4534 ULONG NrSegments;
4535 ULONG_PTR ImageBase;
4536 ULONG ImageSize;
4537 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4538 PMM_SECTION_SEGMENT SectionSegments;
4539
4540 ImageSectionObject = Section->ImageSection;
4541 SectionSegments = ImageSectionObject->Segments;
4542 NrSegments = ImageSectionObject->NrSegments;
4543
4544
4545 ImageBase = (ULONG_PTR)*BaseAddress;
4546 if (ImageBase == 0)
4547 {
4548 ImageBase = ImageSectionObject->ImageBase;
4549 }
4550
4551 ImageSize = 0;
4552 for (i = 0; i < NrSegments; i++)
4553 {
4554 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4555 {
4556 ULONG_PTR MaxExtent;
4557 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4558 SectionSegments[i].Length;
4559 ImageSize = max(ImageSize, MaxExtent);
4560 }
4561 }
4562
4563 ImageSectionObject->ImageSize = ImageSize;
4564
4565 /* Check there is enough space to map the section at that point. */
4566 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4567 PAGE_ROUND_UP(ImageSize)) != NULL)
4568 {
4569 /* Fail if the user requested a fixed base address. */
4570 if ((*BaseAddress) != NULL)
4571 {
4572 MmUnlockAddressSpace(AddressSpace);
4573 return(STATUS_UNSUCCESSFUL);
4574 }
4575 /* Otherwise find a gap to map the image. */
4576 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4577 if (ImageBase == 0)
4578 {
4579 MmUnlockAddressSpace(AddressSpace);
4580 return(STATUS_UNSUCCESSFUL);
4581 }
4582 }
4583
4584 for (i = 0; i < NrSegments; i++)
4585 {
4586 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4587 {
4588 PVOID SBaseAddress = (PVOID)
4589 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4590 MmLockSectionSegment(&SectionSegments[i]);
4591 Status = MmMapViewOfSegment(AddressSpace,
4592 Section,
4593 &SectionSegments[i],
4594 &SBaseAddress,
4595 SectionSegments[i].Length,
4596 SectionSegments[i].Protection,
4597 0,
4598 0);
4599 MmUnlockSectionSegment(&SectionSegments[i]);
4600 if (!NT_SUCCESS(Status))
4601 {
4602 MmUnlockAddressSpace(AddressSpace);
4603 return(Status);
4604 }
4605 }
4606 }
4607
4608 *BaseAddress = (PVOID)ImageBase;
4609 }
4610 else
4611 {
4612 /* check for write access */
4613 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4614 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4615 {
4616 CHECKPOINT1;
4617 return STATUS_SECTION_PROTECTION;
4618 }
4619 /* check for read access */
4620 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4621 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4622 {
4623 CHECKPOINT1;
4624 return STATUS_SECTION_PROTECTION;
4625 }
4626 /* check for execute access */
4627 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4628 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4629 {
4630 CHECKPOINT1;
4631 return STATUS_SECTION_PROTECTION;
4632 }
4633
4634 if (ViewSize == NULL)
4635 {
4636 /* Following this pointer would lead to us to the dark side */
4637 /* What to do? Bugcheck? Return status? Do the mambo? */
4638 KEBUGCHECK(MEMORY_MANAGEMENT);
4639 }
4640
4641 if (SectionOffset == NULL)
4642 {
4643 ViewOffset = 0;
4644 }
4645 else
4646 {
4647 ViewOffset = SectionOffset->u.LowPart;
4648 }
4649
4650 if ((ViewOffset % PAGE_SIZE) != 0)
4651 {
4652 MmUnlockAddressSpace(AddressSpace);
4653 return(STATUS_MAPPED_ALIGNMENT);
4654 }
4655
4656 if ((*ViewSize) == 0)
4657 {
4658 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4659 }
4660 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4661 {
4662 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4663 }
4664
4665 MmLockSectionSegment(Section->Segment);
4666 Status = MmMapViewOfSegment(AddressSpace,
4667 Section,
4668 Section->Segment,
4669 BaseAddress,
4670 *ViewSize,
4671 Protect,
4672 ViewOffset,
4673 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4674 MmUnlockSectionSegment(Section->Segment);
4675 if (!NT_SUCCESS(Status))
4676 {
4677 MmUnlockAddressSpace(AddressSpace);
4678 return(Status);
4679 }
4680 }
4681
4682 MmUnlockAddressSpace(AddressSpace);
4683
4684 return(STATUS_SUCCESS);
4685 }
4686
4687 /*
4688 * @unimplemented
4689 */
4690 BOOLEAN STDCALL
4691 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4692 IN PLARGE_INTEGER NewFileSize)
4693 {
4694 UNIMPLEMENTED;
4695 return (FALSE);
4696 }
4697
4698
4699 /*
4700 * @unimplemented
4701 */
4702 BOOLEAN STDCALL
4703 MmDisableModifiedWriteOfSection (ULONG Unknown0)
4704 {
4705 UNIMPLEMENTED;
4706 return (FALSE);
4707 }
4708
4709 /*
4710 * @implemented
4711 */
4712 BOOLEAN STDCALL
4713 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4714 IN MMFLUSH_TYPE FlushType)
4715 {
4716 switch(FlushType)
4717 {
4718 case MmFlushForDelete:
4719 if (SectionObjectPointer->ImageSectionObject ||
4720 SectionObjectPointer->DataSectionObject)
4721 {
4722 return FALSE;
4723 }
4724 CcRosSetRemoveOnClose(SectionObjectPointer);
4725 return TRUE;
4726 case MmFlushForWrite:
4727 break;
4728 }
4729 return FALSE;
4730 }
4731
4732 /*
4733 * @unimplemented
4734 */
4735 BOOLEAN STDCALL
4736 MmForceSectionClosed (
4737 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4738 IN BOOLEAN DelayClose)
4739 {
4740 UNIMPLEMENTED;
4741 return (FALSE);
4742 }
4743
4744
4745 /*
4746 * @implemented
4747 */
4748 NTSTATUS STDCALL
4749 MmMapViewInSystemSpace (IN PVOID SectionObject,
4750 OUT PVOID * MappedBase,
4751 IN OUT PULONG ViewSize)
4752 {
4753 PROS_SECTION_OBJECT Section;
4754 PMADDRESS_SPACE AddressSpace;
4755 NTSTATUS Status;
4756
4757 DPRINT("MmMapViewInSystemSpace() called\n");
4758
4759 Section = (PROS_SECTION_OBJECT)SectionObject;
4760 AddressSpace = MmGetKernelAddressSpace();
4761
4762 MmLockAddressSpace(AddressSpace);
4763
4764
4765 if ((*ViewSize) == 0)
4766 {
4767 (*ViewSize) = Section->MaximumSize.u.LowPart;
4768 }
4769 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4770 {
4771 (*ViewSize) = Section->MaximumSize.u.LowPart;
4772 }
4773
4774 MmLockSectionSegment(Section->Segment);
4775
4776
4777 Status = MmMapViewOfSegment(AddressSpace,
4778 Section,
4779 Section->Segment,
4780 MappedBase,
4781 *ViewSize,
4782 PAGE_READWRITE,
4783 0,
4784 0);
4785
4786 MmUnlockSectionSegment(Section->Segment);
4787 MmUnlockAddressSpace(AddressSpace);
4788
4789 return Status;
4790 }
4791
4792 /*
4793 * @unimplemented
4794 */
4795 NTSTATUS
4796 STDCALL
4797 MmMapViewInSessionSpace (
4798 IN PVOID Section,
4799 OUT PVOID *MappedBase,
4800 IN OUT PSIZE_T ViewSize
4801 )
4802 {
4803 UNIMPLEMENTED;
4804 return STATUS_NOT_IMPLEMENTED;
4805 }
4806
4807
4808 /*
4809 * @implemented
4810 */
4811 NTSTATUS STDCALL
4812 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4813 {
4814 PMADDRESS_SPACE AddressSpace;
4815 NTSTATUS Status;
4816
4817 DPRINT("MmUnmapViewInSystemSpace() called\n");
4818
4819 AddressSpace = MmGetKernelAddressSpace();
4820
4821 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4822
4823 return Status;
4824 }
4825
4826 /*
4827 * @unimplemented
4828 */
4829 NTSTATUS
4830 STDCALL
4831 MmUnmapViewInSessionSpace (
4832 IN PVOID MappedBase
4833 )
4834 {
4835 UNIMPLEMENTED;
4836 return STATUS_NOT_IMPLEMENTED;
4837 }
4838
4839 /*
4840 * @unimplemented
4841 */
4842 NTSTATUS STDCALL
4843 MmSetBankedSection (ULONG Unknown0,
4844 ULONG Unknown1,
4845 ULONG Unknown2,
4846 ULONG Unknown3,
4847 ULONG Unknown4,
4848 ULONG Unknown5)
4849 {
4850 UNIMPLEMENTED;
4851 return (STATUS_NOT_IMPLEMENTED);
4852 }
4853
4854
4855 /**********************************************************************
4856 * NAME EXPORTED
4857 * MmCreateSection@
4858 *
4859 * DESCRIPTION
4860 * Creates a section object.
4861 *
4862 * ARGUMENTS
4863 * SectionObject (OUT)
4864 * Caller supplied storage for the resulting pointer
4865 * to a SECTION_OBJECT instance;
4866 *
4867 * DesiredAccess
4868 * Specifies the desired access to the section can be a
4869 * combination of:
4870 * STANDARD_RIGHTS_REQUIRED |
4871 * SECTION_QUERY |
4872 * SECTION_MAP_WRITE |
4873 * SECTION_MAP_READ |
4874 * SECTION_MAP_EXECUTE
4875 *
4876 * ObjectAttributes [OPTIONAL]
4877 * Initialized attributes for the object can be used
4878 * to create a named section;
4879 *
4880 * MaximumSize
4881 * Maximizes the size of the memory section. Must be
4882 * non-NULL for a page-file backed section.
4883 * If value specified for a mapped file and the file is
4884 * not large enough, file will be extended.
4885 *
4886 * SectionPageProtection
4887 * Can be a combination of:
4888 * PAGE_READONLY |
4889 * PAGE_READWRITE |
4890 * PAGE_WRITEONLY |
4891 * PAGE_WRITECOPY
4892 *
4893 * AllocationAttributes
4894 * Can be a combination of:
4895 * SEC_IMAGE |
4896 * SEC_RESERVE
4897 *
4898 * FileHandle
4899 * Handle to a file to create a section mapped to a file
4900 * instead of a memory backed section;
4901 *
4902 * File
4903 * Unknown.
4904 *
4905 * RETURN VALUE
4906 * Status.
4907 *
4908 * @implemented
4909 */
4910 NTSTATUS STDCALL
4911 MmCreateSection (OUT PVOID * Section,
4912 IN ACCESS_MASK DesiredAccess,
4913 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4914 IN PLARGE_INTEGER MaximumSize,
4915 IN ULONG SectionPageProtection,
4916 IN ULONG AllocationAttributes,
4917 IN HANDLE FileHandle OPTIONAL,
4918 IN PFILE_OBJECT File OPTIONAL)
4919 {
4920 ULONG Protection;
4921 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4922
4923 /*
4924 * Check the protection
4925 */
4926 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
4927 if (Protection != PAGE_NOACCESS &&
4928 Protection != PAGE_READONLY &&
4929 Protection != PAGE_READWRITE &&
4930 Protection != PAGE_WRITECOPY &&
4931 Protection != PAGE_EXECUTE &&
4932 Protection != PAGE_EXECUTE_READ &&
4933 Protection != PAGE_EXECUTE_READWRITE &&
4934 Protection != PAGE_EXECUTE_WRITECOPY)
4935 {
4936 CHECKPOINT1;
4937 return STATUS_INVALID_PAGE_PROTECTION;
4938 }
4939
4940 if (AllocationAttributes & SEC_IMAGE)
4941 {
4942 return(MmCreateImageSection(SectionObject,
4943 DesiredAccess,
4944 ObjectAttributes,
4945 MaximumSize,
4946 SectionPageProtection,
4947 AllocationAttributes,
4948 FileHandle));
4949 }
4950
4951 if (FileHandle != NULL)
4952 {
4953 return(MmCreateDataFileSection(SectionObject,
4954 DesiredAccess,
4955 ObjectAttributes,
4956 MaximumSize,
4957 SectionPageProtection,
4958 AllocationAttributes,
4959 FileHandle));
4960 }
4961
4962 return(MmCreatePageFileSection(SectionObject,
4963 DesiredAccess,
4964 ObjectAttributes,
4965 MaximumSize,
4966 SectionPageProtection,
4967 AllocationAttributes));
4968 }
4969
4970 NTSTATUS
4971 NTAPI
4972 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
4973 IN OUT PULONG NumberOfPages,
4974 IN OUT PULONG UserPfnArray)
4975 {
4976 UNIMPLEMENTED;
4977 return STATUS_NOT_IMPLEMENTED;
4978 }
4979
4980 NTSTATUS
4981 NTAPI
4982 NtMapUserPhysicalPages(IN PVOID *VirtualAddresses,
4983 IN ULONG NumberOfPages,
4984 IN OUT PULONG UserPfnArray)
4985 {
4986 UNIMPLEMENTED;
4987 return STATUS_NOT_IMPLEMENTED;
4988 }
4989
4990 NTSTATUS
4991 NTAPI
4992 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
4993 IN ULONG NumberOfPages,
4994 IN OUT PULONG UserPfnArray)
4995 {
4996 UNIMPLEMENTED;
4997 return STATUS_NOT_IMPLEMENTED;
4998 }
4999
5000 NTSTATUS
5001 NTAPI
5002 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
5003 IN OUT PULONG NumberOfPages,
5004 IN OUT PULONG UserPfnArray)
5005 {
5006 UNIMPLEMENTED;
5007 return STATUS_NOT_IMPLEMENTED;
5008 }
5009
5010 NTSTATUS
5011 NTAPI
5012 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
5013 IN PVOID File2MappedAsFile)
5014 {
5015 UNIMPLEMENTED;
5016 return STATUS_NOT_IMPLEMENTED;
5017 }
5018
5019
5020 /* EOF */