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