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