[CMAKE]
[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 SIZE_T 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_NUMBER 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_NUMBER 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_NUMBER 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_NUMBER 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_NUMBER OldPage;
1271 PFN_NUMBER 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_NUMBER 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_NUMBER 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_NUMBER 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_NUMBER 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 PSIZE_T 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_NUMBER 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 PMM_SECTION_SEGMENT EffectiveSegment;
2967
2968 if (Flags & EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED)
2969 {
2970 MmspAssertSegmentsPageAligned(ImageSectionObject);
2971 return TRUE;
2972 }
2973
2974 LastSegment = 0;
2975 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
2976
2977 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
2978 {
2979 /*
2980 * The first segment requires special handling
2981 */
2982 if (i == 0)
2983 {
2984 ULONG_PTR VirtualAddress;
2985 ULONG_PTR VirtualOffset;
2986
2987 VirtualAddress = EffectiveSegment->VirtualAddress;
2988
2989 /* Round down the virtual address to the nearest page */
2990 EffectiveSegment->VirtualAddress = PAGE_ROUND_DOWN(VirtualAddress);
2991
2992 /* Round up the virtual size to the nearest page */
2993 EffectiveSegment->Length = PAGE_ROUND_UP(VirtualAddress + EffectiveSegment->Length) -
2994 EffectiveSegment->VirtualAddress;
2995
2996 /* Adjust the raw address and size */
2997 VirtualOffset = VirtualAddress - EffectiveSegment->VirtualAddress;
2998
2999 if (EffectiveSegment->FileOffset < VirtualOffset)
3000 {
3001 return FALSE;
3002 }
3003
3004 /*
3005 * Garbage in, garbage out: unaligned base addresses make the file
3006 * offset point in curious and odd places, but that's what we were
3007 * asked for
3008 */
3009 EffectiveSegment->FileOffset -= VirtualOffset;
3010 EffectiveSegment->RawLength += VirtualOffset;
3011 }
3012 else
3013 {
3014 PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
3015 ULONG_PTR EndOfEffectiveSegment;
3016
3017 EndOfEffectiveSegment = EffectiveSegment->VirtualAddress + EffectiveSegment->Length;
3018 ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
3019
3020 /*
3021 * The current segment begins exactly where the current effective
3022 * segment ended, therefore beginning a new effective segment
3023 */
3024 if (EndOfEffectiveSegment == Segment->VirtualAddress)
3025 {
3026 LastSegment ++;
3027 ASSERT(LastSegment <= i);
3028 ASSERT(LastSegment < ImageSectionObject->NrSegments);
3029
3030 EffectiveSegment = &ImageSectionObject->Segments[LastSegment];
3031
3032 if (LastSegment != i)
3033 {
3034 /*
3035 * Copy the current segment. If necessary, the effective segment
3036 * will be expanded later
3037 */
3038 *EffectiveSegment = *Segment;
3039 }
3040
3041 /*
3042 * Page-align the virtual size. We know for sure the virtual address
3043 * already is
3044 */
3045 ASSERT((EffectiveSegment->VirtualAddress % PAGE_SIZE) == 0);
3046 EffectiveSegment->Length = PAGE_ROUND_UP(EffectiveSegment->Length);
3047 }
3048 /*
3049 * The current segment is still part of the current effective segment:
3050 * extend the effective segment to reflect this
3051 */
3052 else if (EndOfEffectiveSegment > Segment->VirtualAddress)
3053 {
3054 static const ULONG FlagsToProtection[16] =
3055 {
3056 PAGE_NOACCESS,
3057 PAGE_READONLY,
3058 PAGE_READWRITE,
3059 PAGE_READWRITE,
3060 PAGE_EXECUTE_READ,
3061 PAGE_EXECUTE_READ,
3062 PAGE_EXECUTE_READWRITE,
3063 PAGE_EXECUTE_READWRITE,
3064 PAGE_WRITECOPY,
3065 PAGE_WRITECOPY,
3066 PAGE_WRITECOPY,
3067 PAGE_WRITECOPY,
3068 PAGE_EXECUTE_WRITECOPY,
3069 PAGE_EXECUTE_WRITECOPY,
3070 PAGE_EXECUTE_WRITECOPY,
3071 PAGE_EXECUTE_WRITECOPY
3072 };
3073
3074 unsigned ProtectionFlags;
3075
3076 /*
3077 * Extend the file size
3078 */
3079
3080 /* Unaligned segments must be contiguous within the file */
3081 if (Segment->FileOffset != (EffectiveSegment->FileOffset +
3082 EffectiveSegment->RawLength))
3083 {
3084 return FALSE;
3085 }
3086
3087 EffectiveSegment->RawLength += Segment->RawLength;
3088
3089 /*
3090 * Extend the virtual size
3091 */
3092 ASSERT(PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) >= EndOfEffectiveSegment);
3093
3094 EffectiveSegment->Length = PAGE_ROUND_UP(Segment->VirtualAddress + Segment->Length) -
3095 EffectiveSegment->VirtualAddress;
3096
3097 /*
3098 * Merge the protection
3099 */
3100 EffectiveSegment->Protection |= Segment->Protection;
3101
3102 /* Clean up redundance */
3103 ProtectionFlags = 0;
3104
3105 if(EffectiveSegment->Protection & PAGE_IS_READABLE)
3106 ProtectionFlags |= 1 << 0;
3107
3108 if(EffectiveSegment->Protection & PAGE_IS_WRITABLE)
3109 ProtectionFlags |= 1 << 1;
3110
3111 if(EffectiveSegment->Protection & PAGE_IS_EXECUTABLE)
3112 ProtectionFlags |= 1 << 2;
3113
3114 if(EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3115 ProtectionFlags |= 1 << 3;
3116
3117 ASSERT(ProtectionFlags < 16);
3118 EffectiveSegment->Protection = FlagsToProtection[ProtectionFlags];
3119
3120 /* If a segment was required to be shared and cannot, fail */
3121 if(!(Segment->Protection & PAGE_IS_WRITECOPY) &&
3122 EffectiveSegment->Protection & PAGE_IS_WRITECOPY)
3123 {
3124 return FALSE;
3125 }
3126 }
3127 /*
3128 * We assume no holes between segments at this point
3129 */
3130 else
3131 {
3132 KeBugCheck(MEMORY_MANAGEMENT);
3133 }
3134 }
3135 }
3136 ImageSectionObject->NrSegments = LastSegment + 1;
3137
3138 return TRUE;
3139 }
3140
3141 NTSTATUS
3142 ExeFmtpCreateImageSection(HANDLE FileHandle,
3143 PMM_IMAGE_SECTION_OBJECT ImageSectionObject)
3144 {
3145 LARGE_INTEGER Offset;
3146 PVOID FileHeader;
3147 PVOID FileHeaderBuffer;
3148 ULONG FileHeaderSize;
3149 ULONG Flags;
3150 ULONG OldNrSegments;
3151 NTSTATUS Status;
3152 ULONG i;
3153
3154 /*
3155 * Read the beginning of the file (2 pages). Should be enough to contain
3156 * all (or most) of the headers
3157 */
3158 Offset.QuadPart = 0;
3159
3160 /* FIXME: use FileObject instead of FileHandle */
3161 Status = ExeFmtpReadFile (FileHandle,
3162 &Offset,
3163 PAGE_SIZE * 2,
3164 &FileHeader,
3165 &FileHeaderBuffer,
3166 &FileHeaderSize);
3167
3168 if (!NT_SUCCESS(Status))
3169 return Status;
3170
3171 if (FileHeaderSize == 0)
3172 {
3173 ExFreePool(FileHeaderBuffer);
3174 return STATUS_UNSUCCESSFUL;
3175 }
3176
3177 /*
3178 * Look for a loader that can handle this executable
3179 */
3180 for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
3181 {
3182 RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
3183 Flags = 0;
3184
3185 /* FIXME: use FileObject instead of FileHandle */
3186 Status = ExeFmtpLoaders[i](FileHeader,
3187 FileHeaderSize,
3188 FileHandle,
3189 ImageSectionObject,
3190 &Flags,
3191 ExeFmtpReadFile,
3192 ExeFmtpAllocateSegments);
3193
3194 if (!NT_SUCCESS(Status))
3195 {
3196 if (ImageSectionObject->Segments)
3197 {
3198 ExFreePool(ImageSectionObject->Segments);
3199 ImageSectionObject->Segments = NULL;
3200 }
3201 }
3202
3203 if (Status != STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3204 break;
3205 }
3206
3207 ExFreePoolWithTag(FileHeaderBuffer, 'rXmM');
3208
3209 /*
3210 * No loader handled the format
3211 */
3212 if (Status == STATUS_ROS_EXEFMT_UNKNOWN_FORMAT)
3213 {
3214 Status = STATUS_INVALID_IMAGE_NOT_MZ;
3215 ASSERT(!NT_SUCCESS(Status));
3216 }
3217
3218 if (!NT_SUCCESS(Status))
3219 return Status;
3220
3221 ASSERT(ImageSectionObject->Segments != NULL);
3222
3223 /*
3224 * Some defaults
3225 */
3226 /* FIXME? are these values platform-dependent? */
3227 if(ImageSectionObject->StackReserve == 0)
3228 ImageSectionObject->StackReserve = 0x40000;
3229
3230 if(ImageSectionObject->StackCommit == 0)
3231 ImageSectionObject->StackCommit = 0x1000;
3232
3233 if(ImageSectionObject->ImageBase == 0)
3234 {
3235 if(ImageSectionObject->ImageCharacteristics & IMAGE_FILE_DLL)
3236 ImageSectionObject->ImageBase = 0x10000000;
3237 else
3238 ImageSectionObject->ImageBase = 0x00400000;
3239 }
3240
3241 /*
3242 * And now the fun part: fixing the segments
3243 */
3244
3245 /* Sort them by virtual address */
3246 MmspSortSegments(ImageSectionObject, Flags);
3247
3248 /* Ensure they don't overlap in memory */
3249 if (!MmspCheckSegmentBounds(ImageSectionObject, Flags))
3250 return STATUS_INVALID_IMAGE_FORMAT;
3251
3252 /* Ensure they are aligned */
3253 OldNrSegments = ImageSectionObject->NrSegments;
3254
3255 if (!MmspPageAlignSegments(ImageSectionObject, Flags))
3256 return STATUS_INVALID_IMAGE_FORMAT;
3257
3258 /* Trim them if the alignment phase merged some of them */
3259 if (ImageSectionObject->NrSegments < OldNrSegments)
3260 {
3261 PMM_SECTION_SEGMENT Segments;
3262 SIZE_T SizeOfSegments;
3263
3264 SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments;
3265
3266 Segments = ExAllocatePoolWithTag(PagedPool,
3267 SizeOfSegments,
3268 TAG_MM_SECTION_SEGMENT);
3269
3270 if (Segments == NULL)
3271 return STATUS_INSUFFICIENT_RESOURCES;
3272
3273 RtlCopyMemory(Segments, ImageSectionObject->Segments, SizeOfSegments);
3274 ExFreePool(ImageSectionObject->Segments);
3275 ImageSectionObject->Segments = Segments;
3276 }
3277
3278 /* And finish their initialization */
3279 for ( i = 0; i < ImageSectionObject->NrSegments; ++ i )
3280 {
3281 ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock);
3282 ImageSectionObject->Segments[i].ReferenceCount = 1;
3283
3284 RtlZeroMemory(&ImageSectionObject->Segments[i].PageDirectory,
3285 sizeof(ImageSectionObject->Segments[i].PageDirectory));
3286 }
3287
3288 ASSERT(NT_SUCCESS(Status));
3289 return Status;
3290 }
3291
3292 NTSTATUS
3293 MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
3294 ACCESS_MASK DesiredAccess,
3295 POBJECT_ATTRIBUTES ObjectAttributes,
3296 PLARGE_INTEGER UMaximumSize,
3297 ULONG SectionPageProtection,
3298 ULONG AllocationAttributes,
3299 HANDLE FileHandle)
3300 {
3301 PROS_SECTION_OBJECT Section;
3302 NTSTATUS Status;
3303 PFILE_OBJECT FileObject;
3304 PMM_SECTION_SEGMENT SectionSegments;
3305 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3306 ULONG i;
3307 ULONG FileAccess = 0;
3308
3309 /*
3310 * Specifying a maximum size is meaningless for an image section
3311 */
3312 if (UMaximumSize != NULL)
3313 {
3314 return(STATUS_INVALID_PARAMETER_4);
3315 }
3316
3317 /*
3318 * Check file access required
3319 */
3320 if (SectionPageProtection & PAGE_READWRITE ||
3321 SectionPageProtection & PAGE_EXECUTE_READWRITE)
3322 {
3323 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
3324 }
3325 else
3326 {
3327 FileAccess = FILE_READ_DATA;
3328 }
3329
3330 /*
3331 * Reference the file handle
3332 */
3333 Status = ObReferenceObjectByHandle(FileHandle,
3334 FileAccess,
3335 IoFileObjectType,
3336 ExGetPreviousMode(),
3337 (PVOID*)(PVOID)&FileObject,
3338 NULL);
3339
3340 if (!NT_SUCCESS(Status))
3341 {
3342 return Status;
3343 }
3344
3345 /*
3346 * Create the section
3347 */
3348 Status = ObCreateObject (ExGetPreviousMode(),
3349 MmSectionObjectType,
3350 ObjectAttributes,
3351 ExGetPreviousMode(),
3352 NULL,
3353 sizeof(ROS_SECTION_OBJECT),
3354 0,
3355 0,
3356 (PVOID*)(PVOID)&Section);
3357 if (!NT_SUCCESS(Status))
3358 {
3359 ObDereferenceObject(FileObject);
3360 return(Status);
3361 }
3362
3363 /*
3364 * Initialize it
3365 */
3366 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
3367 Section->SectionPageProtection = SectionPageProtection;
3368 Section->AllocationAttributes = AllocationAttributes;
3369
3370 /*
3371 * Initialized caching for this file object if previously caching
3372 * was initialized for the same on disk file
3373 */
3374 Status = CcTryToInitializeFileCache(FileObject);
3375
3376 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
3377 {
3378 NTSTATUS StatusExeFmt;
3379
3380 ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT);
3381 if (ImageSectionObject == NULL)
3382 {
3383 ObDereferenceObject(FileObject);
3384 ObDereferenceObject(Section);
3385 return(STATUS_NO_MEMORY);
3386 }
3387
3388 RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
3389
3390 StatusExeFmt = ExeFmtpCreateImageSection(FileHandle, ImageSectionObject);
3391
3392 if (!NT_SUCCESS(StatusExeFmt))
3393 {
3394 if(ImageSectionObject->Segments != NULL)
3395 ExFreePool(ImageSectionObject->Segments);
3396
3397 ExFreePool(ImageSectionObject);
3398 ObDereferenceObject(Section);
3399 ObDereferenceObject(FileObject);
3400 return(StatusExeFmt);
3401 }
3402
3403 Section->ImageSection = ImageSectionObject;
3404 ASSERT(ImageSectionObject->Segments);
3405
3406 /*
3407 * Lock the file
3408 */
3409 Status = MmspWaitForFileLock(FileObject);
3410 if (!NT_SUCCESS(Status))
3411 {
3412 ExFreePool(ImageSectionObject->Segments);
3413 ExFreePool(ImageSectionObject);
3414 ObDereferenceObject(Section);
3415 ObDereferenceObject(FileObject);
3416 return(Status);
3417 }
3418
3419 if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject,
3420 ImageSectionObject, NULL))
3421 {
3422 /*
3423 * An other thread has initialized the same image in the background
3424 */
3425 ExFreePool(ImageSectionObject->Segments);
3426 ExFreePool(ImageSectionObject);
3427 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3428 Section->ImageSection = ImageSectionObject;
3429 SectionSegments = ImageSectionObject->Segments;
3430
3431 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3432 {
3433 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3434 }
3435 }
3436
3437 Status = StatusExeFmt;
3438 }
3439 else
3440 {
3441 /*
3442 * Lock the file
3443 */
3444 Status = MmspWaitForFileLock(FileObject);
3445 if (Status != STATUS_SUCCESS)
3446 {
3447 ObDereferenceObject(Section);
3448 ObDereferenceObject(FileObject);
3449 return(Status);
3450 }
3451
3452 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
3453 Section->ImageSection = ImageSectionObject;
3454 SectionSegments = ImageSectionObject->Segments;
3455
3456 /*
3457 * Otherwise just reference all the section segments
3458 */
3459 for (i = 0; i < ImageSectionObject->NrSegments; i++)
3460 {
3461 (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount);
3462 }
3463
3464 Status = STATUS_SUCCESS;
3465 }
3466 Section->FileObject = FileObject;
3467 CcRosReferenceCache(FileObject);
3468 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3469 *SectionObject = Section;
3470 return(Status);
3471 }
3472
3473 /*
3474 * @implemented
3475 */
3476 NTSTATUS NTAPI
3477 NtCreateSection (OUT PHANDLE SectionHandle,
3478 IN ACCESS_MASK DesiredAccess,
3479 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3480 IN PLARGE_INTEGER MaximumSize OPTIONAL,
3481 IN ULONG SectionPageProtection OPTIONAL,
3482 IN ULONG AllocationAttributes,
3483 IN HANDLE FileHandle OPTIONAL)
3484 {
3485 LARGE_INTEGER SafeMaximumSize;
3486 PVOID SectionObject;
3487 KPROCESSOR_MODE PreviousMode;
3488 NTSTATUS Status;
3489
3490 PreviousMode = ExGetPreviousMode();
3491
3492 if(PreviousMode != KernelMode)
3493 {
3494 _SEH2_TRY
3495 {
3496 if (MaximumSize != NULL)
3497 {
3498 /* make a copy on the stack */
3499 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
3500 MaximumSize = &SafeMaximumSize;
3501 }
3502 ProbeForWriteHandle(SectionHandle);
3503 }
3504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3505 {
3506 /* Return the exception code */
3507 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3508 }
3509 _SEH2_END;
3510 }
3511
3512 Status = MmCreateSection(&SectionObject,
3513 DesiredAccess,
3514 ObjectAttributes,
3515 MaximumSize,
3516 SectionPageProtection,
3517 AllocationAttributes,
3518 FileHandle,
3519 NULL);
3520 if (NT_SUCCESS(Status))
3521 {
3522 Status = ObInsertObject ((PVOID)SectionObject,
3523 NULL,
3524 DesiredAccess,
3525 0,
3526 NULL,
3527 SectionHandle);
3528 }
3529
3530 return Status;
3531 }
3532
3533
3534 /**********************************************************************
3535 * NAME
3536 * NtOpenSection
3537 *
3538 * DESCRIPTION
3539 *
3540 * ARGUMENTS
3541 * SectionHandle
3542 *
3543 * DesiredAccess
3544 *
3545 * ObjectAttributes
3546 *
3547 * RETURN VALUE
3548 *
3549 * REVISIONS
3550 */
3551 NTSTATUS NTAPI
3552 NtOpenSection(PHANDLE SectionHandle,
3553 ACCESS_MASK DesiredAccess,
3554 POBJECT_ATTRIBUTES ObjectAttributes)
3555 {
3556 HANDLE hSection;
3557 KPROCESSOR_MODE PreviousMode;
3558 NTSTATUS Status;
3559
3560 PreviousMode = ExGetPreviousMode();
3561
3562 if(PreviousMode != KernelMode)
3563 {
3564 _SEH2_TRY
3565 {
3566 ProbeForWriteHandle(SectionHandle);
3567 }
3568 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3569 {
3570 /* Return the exception code */
3571 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3572 }
3573 _SEH2_END;
3574 }
3575
3576 Status = ObOpenObjectByName(ObjectAttributes,
3577 MmSectionObjectType,
3578 PreviousMode,
3579 NULL,
3580 DesiredAccess,
3581 NULL,
3582 &hSection);
3583
3584 if(NT_SUCCESS(Status))
3585 {
3586 _SEH2_TRY
3587 {
3588 *SectionHandle = hSection;
3589 }
3590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3591 {
3592 Status = _SEH2_GetExceptionCode();
3593 }
3594 _SEH2_END;
3595 }
3596
3597 return(Status);
3598 }
3599
3600 static NTSTATUS
3601 MmMapViewOfSegment(PMMSUPPORT AddressSpace,
3602 PROS_SECTION_OBJECT Section,
3603 PMM_SECTION_SEGMENT Segment,
3604 PVOID* BaseAddress,
3605 SIZE_T ViewSize,
3606 ULONG Protect,
3607 ULONG ViewOffset,
3608 ULONG AllocationType)
3609 {
3610 PMEMORY_AREA MArea;
3611 NTSTATUS Status;
3612 PHYSICAL_ADDRESS BoundaryAddressMultiple;
3613
3614 BoundaryAddressMultiple.QuadPart = 0;
3615
3616 Status = MmCreateMemoryArea(AddressSpace,
3617 MEMORY_AREA_SECTION_VIEW,
3618 BaseAddress,
3619 ViewSize,
3620 Protect,
3621 &MArea,
3622 FALSE,
3623 AllocationType,
3624 BoundaryAddressMultiple);
3625 if (!NT_SUCCESS(Status))
3626 {
3627 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3628 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
3629 return(Status);
3630 }
3631
3632 ObReferenceObject((PVOID)Section);
3633
3634 MArea->Data.SectionData.Segment = Segment;
3635 MArea->Data.SectionData.Section = Section;
3636 MArea->Data.SectionData.ViewOffset = ViewOffset;
3637 MArea->Data.SectionData.WriteCopyView = FALSE;
3638 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
3639 ViewSize, 0, Protect);
3640
3641 return(STATUS_SUCCESS);
3642 }
3643
3644
3645 /**********************************************************************
3646 * NAME EXPORTED
3647 * NtMapViewOfSection
3648 *
3649 * DESCRIPTION
3650 * Maps a view of a section into the virtual address space of a
3651 * process.
3652 *
3653 * ARGUMENTS
3654 * SectionHandle
3655 * Handle of the section.
3656 *
3657 * ProcessHandle
3658 * Handle of the process.
3659 *
3660 * BaseAddress
3661 * Desired base address (or NULL) on entry;
3662 * Actual base address of the view on exit.
3663 *
3664 * ZeroBits
3665 * Number of high order address bits that must be zero.
3666 *
3667 * CommitSize
3668 * Size in bytes of the initially committed section of
3669 * the view.
3670 *
3671 * SectionOffset
3672 * Offset in bytes from the beginning of the section
3673 * to the beginning of the view.
3674 *
3675 * ViewSize
3676 * Desired length of map (or zero to map all) on entry
3677 * Actual length mapped on exit.
3678 *
3679 * InheritDisposition
3680 * Specified how the view is to be shared with
3681 * child processes.
3682 *
3683 * AllocateType
3684 * Type of allocation for the pages.
3685 *
3686 * Protect
3687 * Protection for the committed region of the view.
3688 *
3689 * RETURN VALUE
3690 * Status.
3691 *
3692 * @implemented
3693 */
3694 NTSTATUS NTAPI
3695 NtMapViewOfSection(IN HANDLE SectionHandle,
3696 IN HANDLE ProcessHandle,
3697 IN OUT PVOID* BaseAddress OPTIONAL,
3698 IN ULONG_PTR ZeroBits OPTIONAL,
3699 IN SIZE_T CommitSize,
3700 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3701 IN OUT PSIZE_T ViewSize,
3702 IN SECTION_INHERIT InheritDisposition,
3703 IN ULONG AllocationType OPTIONAL,
3704 IN ULONG Protect)
3705 {
3706 PVOID SafeBaseAddress;
3707 LARGE_INTEGER SafeSectionOffset;
3708 SIZE_T SafeViewSize;
3709 PROS_SECTION_OBJECT Section;
3710 PEPROCESS Process;
3711 KPROCESSOR_MODE PreviousMode;
3712 NTSTATUS Status;
3713 ULONG tmpProtect;
3714 ACCESS_MASK DesiredAccess;
3715
3716 /*
3717 * Check the protection
3718 */
3719 if (Protect & ~PAGE_FLAGS_VALID_FROM_USER_MODE)
3720 {
3721 return STATUS_INVALID_PARAMETER_10;
3722 }
3723
3724 tmpProtect = Protect & ~(PAGE_GUARD|PAGE_NOCACHE);
3725 if (tmpProtect != PAGE_NOACCESS &&
3726 tmpProtect != PAGE_READONLY &&
3727 tmpProtect != PAGE_READWRITE &&
3728 tmpProtect != PAGE_WRITECOPY &&
3729 tmpProtect != PAGE_EXECUTE &&
3730 tmpProtect != PAGE_EXECUTE_READ &&
3731 tmpProtect != PAGE_EXECUTE_READWRITE &&
3732 tmpProtect != PAGE_EXECUTE_WRITECOPY)
3733 {
3734 return STATUS_INVALID_PAGE_PROTECTION;
3735 }
3736
3737 PreviousMode = ExGetPreviousMode();
3738
3739 if(PreviousMode != KernelMode)
3740 {
3741 SafeBaseAddress = NULL;
3742 SafeSectionOffset.QuadPart = 0;
3743 SafeViewSize = 0;
3744
3745 _SEH2_TRY
3746 {
3747 if(BaseAddress != NULL)
3748 {
3749 ProbeForWritePointer(BaseAddress);
3750 SafeBaseAddress = *BaseAddress;
3751 }
3752 if(SectionOffset != NULL)
3753 {
3754 ProbeForWriteLargeInteger(SectionOffset);
3755 SafeSectionOffset = *SectionOffset;
3756 }
3757 ProbeForWriteSize_t(ViewSize);
3758 SafeViewSize = *ViewSize;
3759 }
3760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3761 {
3762 /* Return the exception code */
3763 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3764 }
3765 _SEH2_END;
3766 }
3767 else
3768 {
3769 SafeBaseAddress = (BaseAddress != NULL ? *BaseAddress : NULL);
3770 SafeSectionOffset.QuadPart = (SectionOffset != NULL ? SectionOffset->QuadPart : 0);
3771 SafeViewSize = (ViewSize != NULL ? *ViewSize : 0);
3772 }
3773
3774 SafeSectionOffset.LowPart = PAGE_ROUND_DOWN(SafeSectionOffset.LowPart);
3775
3776 Status = ObReferenceObjectByHandle(ProcessHandle,
3777 PROCESS_VM_OPERATION,
3778 PsProcessType,
3779 PreviousMode,
3780 (PVOID*)(PVOID)&Process,
3781 NULL);
3782 if (!NT_SUCCESS(Status))
3783 {
3784 return(Status);
3785 }
3786
3787 /* Convert NT Protection Attr to Access Mask */
3788 if (Protect == PAGE_READONLY)
3789 {
3790 DesiredAccess = SECTION_MAP_READ;
3791 }
3792 else if (Protect == PAGE_READWRITE)
3793 {
3794 DesiredAccess = SECTION_MAP_WRITE;
3795 }
3796 else if (Protect == PAGE_WRITECOPY)
3797 {
3798 DesiredAccess = SECTION_QUERY;
3799 }
3800 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3801 else
3802 {
3803 DesiredAccess = SECTION_MAP_READ;
3804 }
3805
3806 Status = ObReferenceObjectByHandle(SectionHandle,
3807 DesiredAccess,
3808 MmSectionObjectType,
3809 PreviousMode,
3810 (PVOID*)(PVOID)&Section,
3811 NULL);
3812 if (!(NT_SUCCESS(Status)))
3813 {
3814 DPRINT("ObReference failed rc=%x\n",Status);
3815 ObDereferenceObject(Process);
3816 return(Status);
3817 }
3818
3819 Status = MmMapViewOfSection(Section,
3820 (PEPROCESS)Process,
3821 (BaseAddress != NULL ? &SafeBaseAddress : NULL),
3822 ZeroBits,
3823 CommitSize,
3824 (SectionOffset != NULL ? &SafeSectionOffset : NULL),
3825 (ViewSize != NULL ? &SafeViewSize : NULL),
3826 InheritDisposition,
3827 AllocationType,
3828 Protect);
3829
3830 /* Check if this is an image for the current process */
3831 if ((Section->AllocationAttributes & SEC_IMAGE) &&
3832 (Process == PsGetCurrentProcess()) &&
3833 (Status != STATUS_IMAGE_NOT_AT_BASE))
3834 {
3835 /* Notify the debugger */
3836 DbgkMapViewOfSection(Section,
3837 SafeBaseAddress,
3838 SafeSectionOffset.LowPart,
3839 SafeViewSize);
3840 }
3841
3842 ObDereferenceObject(Section);
3843 ObDereferenceObject(Process);
3844
3845 if(NT_SUCCESS(Status))
3846 {
3847 /* copy parameters back to the caller */
3848 _SEH2_TRY
3849 {
3850 if(BaseAddress != NULL)
3851 {
3852 *BaseAddress = SafeBaseAddress;
3853 }
3854 if(SectionOffset != NULL)
3855 {
3856 *SectionOffset = SafeSectionOffset;
3857 }
3858 if(ViewSize != NULL)
3859 {
3860 *ViewSize = SafeViewSize;
3861 }
3862 }
3863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3864 {
3865 Status = _SEH2_GetExceptionCode();
3866 }
3867 _SEH2_END;
3868 }
3869
3870 return(Status);
3871 }
3872
3873 static VOID
3874 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3875 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
3876 {
3877 ULONG Entry;
3878 PFILE_OBJECT FileObject;
3879 PBCB Bcb;
3880 ULONG Offset;
3881 SWAPENTRY SavedSwapEntry;
3882 PMM_PAGEOP PageOp;
3883 NTSTATUS Status;
3884 PROS_SECTION_OBJECT Section;
3885 PMM_SECTION_SEGMENT Segment;
3886 PMMSUPPORT AddressSpace;
3887 PEPROCESS Process;
3888
3889 AddressSpace = (PMMSUPPORT)Context;
3890 Process = MmGetAddressSpaceOwner(AddressSpace);
3891
3892 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3893
3894 Offset = ((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress) +
3895 MemoryArea->Data.SectionData.ViewOffset;
3896
3897 Section = MemoryArea->Data.SectionData.Section;
3898 Segment = MemoryArea->Data.SectionData.Segment;
3899
3900 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3901
3902 while (PageOp)
3903 {
3904 MmUnlockSectionSegment(Segment);
3905 MmUnlockAddressSpace(AddressSpace);
3906
3907 Status = MmspWaitForPageOpCompletionEvent(PageOp);
3908 if (Status != STATUS_SUCCESS)
3909 {
3910 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3911 KeBugCheck(MEMORY_MANAGEMENT);
3912 }
3913
3914 MmLockAddressSpace(AddressSpace);
3915 MmLockSectionSegment(Segment);
3916 MmspCompleteAndReleasePageOp(PageOp);
3917 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset);
3918 }
3919
3920 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3921
3922 /*
3923 * For a dirty, datafile, non-private page mark it as dirty in the
3924 * cache manager.
3925 */
3926 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3927 {
3928 if (Page == PFN_FROM_SSE(Entry) && Dirty)
3929 {
3930 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3931 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3932 CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
3933 ASSERT(SwapEntry == 0);
3934 }
3935 }
3936
3937 if (SwapEntry != 0)
3938 {
3939 /*
3940 * Sanity check
3941 */
3942 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3943 {
3944 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3945 KeBugCheck(MEMORY_MANAGEMENT);
3946 }
3947 MmFreeSwapPage(SwapEntry);
3948 }
3949 else if (Page != 0)
3950 {
3951 if (IS_SWAP_FROM_SSE(Entry) ||
3952 Page != PFN_FROM_SSE(Entry))
3953 {
3954 /*
3955 * Sanity check
3956 */
3957 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3958 {
3959 DPRINT1("Found a private page in a pagefile section.\n");
3960 KeBugCheck(MEMORY_MANAGEMENT);
3961 }
3962 /*
3963 * Just dereference private pages
3964 */
3965 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
3966 if (SavedSwapEntry != 0)
3967 {
3968 MmFreeSwapPage(SavedSwapEntry);
3969 MmSetSavedSwapEntryPage(Page, 0);
3970 }
3971 MmDeleteRmap(Page, Process, Address);
3972 MmReleasePageMemoryConsumer(MC_USER, Page);
3973 }
3974 else
3975 {
3976 MmDeleteRmap(Page, Process, Address);
3977 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
3978 }
3979 }
3980 }
3981
3982 static NTSTATUS
3983 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace,
3984 PVOID BaseAddress)
3985 {
3986 NTSTATUS Status;
3987 PMEMORY_AREA MemoryArea;
3988 PROS_SECTION_OBJECT Section;
3989 PMM_SECTION_SEGMENT Segment;
3990 PLIST_ENTRY CurrentEntry;
3991 PMM_REGION CurrentRegion;
3992 PLIST_ENTRY RegionListHead;
3993
3994 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
3995 BaseAddress);
3996 if (MemoryArea == NULL)
3997 {
3998 return(STATUS_UNSUCCESSFUL);
3999 }
4000
4001 MemoryArea->DeleteInProgress = TRUE;
4002 Section = MemoryArea->Data.SectionData.Section;
4003 Segment = MemoryArea->Data.SectionData.Segment;
4004
4005 MmLockSectionSegment(Segment);
4006
4007 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
4008 while (!IsListEmpty(RegionListHead))
4009 {
4010 CurrentEntry = RemoveHeadList(RegionListHead);
4011 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
4012 ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
4013 }
4014
4015 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
4016 {
4017 Status = MmFreeMemoryArea(AddressSpace,
4018 MemoryArea,
4019 NULL,
4020 NULL);
4021 }
4022 else
4023 {
4024 Status = MmFreeMemoryArea(AddressSpace,
4025 MemoryArea,
4026 MmFreeSectionPage,
4027 AddressSpace);
4028 }
4029 MmUnlockSectionSegment(Segment);
4030 ObDereferenceObject(Section);
4031 return(Status);
4032 }
4033
4034 /*
4035 * @implemented
4036 */
4037 NTSTATUS NTAPI
4038 MmUnmapViewOfSection(PEPROCESS Process,
4039 PVOID BaseAddress)
4040 {
4041 NTSTATUS Status;
4042 PMEMORY_AREA MemoryArea;
4043 PMMSUPPORT AddressSpace;
4044 PROS_SECTION_OBJECT Section;
4045 PMM_PAGEOP PageOp;
4046 ULONG_PTR Offset;
4047 PVOID ImageBaseAddress = 0;
4048
4049 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4050 Process, BaseAddress);
4051
4052 ASSERT(Process);
4053
4054 AddressSpace = &Process->Vm;
4055
4056 MmLockAddressSpace(AddressSpace);
4057 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4058 BaseAddress);
4059 if (MemoryArea == NULL ||
4060 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
4061 MemoryArea->DeleteInProgress)
4062 {
4063 MmUnlockAddressSpace(AddressSpace);
4064 return STATUS_NOT_MAPPED_VIEW;
4065 }
4066
4067 MemoryArea->DeleteInProgress = TRUE;
4068
4069 while (MemoryArea->PageOpCount)
4070 {
4071 Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
4072
4073 while (Offset)
4074 {
4075 Offset -= PAGE_SIZE;
4076 PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
4077 MemoryArea->Data.SectionData.Segment,
4078 Offset + MemoryArea->Data.SectionData.ViewOffset);
4079 if (PageOp)
4080 {
4081 MmUnlockAddressSpace(AddressSpace);
4082 Status = MmspWaitForPageOpCompletionEvent(PageOp);
4083 if (Status != STATUS_SUCCESS)
4084 {
4085 DPRINT1("Failed to wait for page op, status = %x\n", Status);
4086 KeBugCheck(MEMORY_MANAGEMENT);
4087 }
4088 MmLockAddressSpace(AddressSpace);
4089 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
4090 BaseAddress);
4091 if (MemoryArea == NULL ||
4092 MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
4093 {
4094 MmUnlockAddressSpace(AddressSpace);
4095 return STATUS_NOT_MAPPED_VIEW;
4096 }
4097 break;
4098 }
4099 }
4100 }
4101
4102 Section = MemoryArea->Data.SectionData.Section;
4103
4104 if (Section->AllocationAttributes & SEC_IMAGE)
4105 {
4106 ULONG i;
4107 ULONG NrSegments;
4108 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4109 PMM_SECTION_SEGMENT SectionSegments;
4110 PMM_SECTION_SEGMENT Segment;
4111
4112 Segment = MemoryArea->Data.SectionData.Segment;
4113 ImageSectionObject = Section->ImageSection;
4114 SectionSegments = ImageSectionObject->Segments;
4115 NrSegments = ImageSectionObject->NrSegments;
4116
4117 /* Search for the current segment within the section segments
4118 * and calculate the image base address */
4119 for (i = 0; i < NrSegments; i++)
4120 {
4121 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4122 {
4123 if (Segment == &SectionSegments[i])
4124 {
4125 ImageBaseAddress = (char*)BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
4126 break;
4127 }
4128 }
4129 }
4130 if (i >= NrSegments)
4131 {
4132 KeBugCheck(MEMORY_MANAGEMENT);
4133 }
4134
4135 for (i = 0; i < NrSegments; i++)
4136 {
4137 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4138 {
4139 PVOID SBaseAddress = (PVOID)
4140 ((char*)ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4141
4142 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
4143 }
4144 }
4145 }
4146 else
4147 {
4148 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
4149 }
4150
4151 MmUnlockAddressSpace(AddressSpace);
4152
4153 /* Notify debugger */
4154 if (ImageBaseAddress) DbgkUnMapViewOfSection(ImageBaseAddress);
4155
4156 return(STATUS_SUCCESS);
4157 }
4158
4159 /**********************************************************************
4160 * NAME EXPORTED
4161 * NtUnmapViewOfSection
4162 *
4163 * DESCRIPTION
4164 *
4165 * ARGUMENTS
4166 * ProcessHandle
4167 *
4168 * BaseAddress
4169 *
4170 * RETURN VALUE
4171 * Status.
4172 *
4173 * REVISIONS
4174 */
4175 NTSTATUS NTAPI
4176 NtUnmapViewOfSection (HANDLE ProcessHandle,
4177 PVOID BaseAddress)
4178 {
4179 PEPROCESS Process;
4180 KPROCESSOR_MODE PreviousMode;
4181 NTSTATUS Status;
4182
4183 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4184 ProcessHandle, BaseAddress);
4185
4186 PreviousMode = ExGetPreviousMode();
4187
4188 DPRINT("Referencing process\n");
4189 Status = ObReferenceObjectByHandle(ProcessHandle,
4190 PROCESS_VM_OPERATION,
4191 PsProcessType,
4192 PreviousMode,
4193 (PVOID*)(PVOID)&Process,
4194 NULL);
4195 if (!NT_SUCCESS(Status))
4196 {
4197 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
4198 return(Status);
4199 }
4200
4201 Status = MmUnmapViewOfSection(Process, BaseAddress);
4202
4203 ObDereferenceObject(Process);
4204
4205 return Status;
4206 }
4207
4208
4209 /**
4210 * Queries the information of a section object.
4211 *
4212 * @param SectionHandle
4213 * Handle to the section object. It must be opened with SECTION_QUERY
4214 * access.
4215 * @param SectionInformationClass
4216 * Index to a certain information structure. Can be either
4217 * SectionBasicInformation or SectionImageInformation. The latter
4218 * is valid only for sections that were created with the SEC_IMAGE
4219 * flag.
4220 * @param SectionInformation
4221 * Caller supplies storage for resulting information.
4222 * @param Length
4223 * Size of the supplied storage.
4224 * @param ResultLength
4225 * Data written.
4226 *
4227 * @return Status.
4228 *
4229 * @implemented
4230 */
4231 NTSTATUS NTAPI
4232 NtQuerySection(IN HANDLE SectionHandle,
4233 IN SECTION_INFORMATION_CLASS SectionInformationClass,
4234 OUT PVOID SectionInformation,
4235 IN SIZE_T SectionInformationLength,
4236 OUT PSIZE_T ResultLength OPTIONAL)
4237 {
4238 PROS_SECTION_OBJECT Section;
4239 KPROCESSOR_MODE PreviousMode;
4240 NTSTATUS Status;
4241 PAGED_CODE();
4242
4243 PreviousMode = ExGetPreviousMode();
4244
4245 Status = DefaultQueryInfoBufferCheck(SectionInformationClass,
4246 ExSectionInfoClass,
4247 sizeof(ExSectionInfoClass) / sizeof(ExSectionInfoClass[0]),
4248 SectionInformation,
4249 SectionInformationLength,
4250 NULL,
4251 ResultLength,
4252 PreviousMode);
4253
4254 if(!NT_SUCCESS(Status))
4255 {
4256 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status);
4257 return Status;
4258 }
4259
4260 Status = ObReferenceObjectByHandle(SectionHandle,
4261 SECTION_QUERY,
4262 MmSectionObjectType,
4263 PreviousMode,
4264 (PVOID*)(PVOID)&Section,
4265 NULL);
4266 if (NT_SUCCESS(Status))
4267 {
4268 switch (SectionInformationClass)
4269 {
4270 case SectionBasicInformation:
4271 {
4272 PSECTION_BASIC_INFORMATION Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
4273
4274 _SEH2_TRY
4275 {
4276 Sbi->Attributes = Section->AllocationAttributes;
4277 if (Section->AllocationAttributes & SEC_IMAGE)
4278 {
4279 Sbi->BaseAddress = 0;
4280 Sbi->Size.QuadPart = 0;
4281 }
4282 else
4283 {
4284 Sbi->BaseAddress = (PVOID)Section->Segment->VirtualAddress;
4285 Sbi->Size.QuadPart = Section->Segment->Length;
4286 }
4287
4288 if (ResultLength != NULL)
4289 {
4290 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
4291 }
4292 Status = STATUS_SUCCESS;
4293 }
4294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4295 {
4296 Status = _SEH2_GetExceptionCode();
4297 }
4298 _SEH2_END;
4299
4300 break;
4301 }
4302
4303 case SectionImageInformation:
4304 {
4305 PSECTION_IMAGE_INFORMATION Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
4306
4307 _SEH2_TRY
4308 {
4309 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
4310 if (Section->AllocationAttributes & SEC_IMAGE)
4311 {
4312 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4313 ImageSectionObject = Section->ImageSection;
4314
4315 Sii->TransferAddress = (PVOID)ImageSectionObject->EntryPoint;
4316 Sii->MaximumStackSize = ImageSectionObject->StackReserve;
4317 Sii->CommittedStackSize = ImageSectionObject->StackCommit;
4318 Sii->SubSystemType = ImageSectionObject->Subsystem;
4319 Sii->SubSystemMinorVersion = ImageSectionObject->MinorSubsystemVersion;
4320 Sii->SubSystemMajorVersion = ImageSectionObject->MajorSubsystemVersion;
4321 Sii->ImageCharacteristics = ImageSectionObject->ImageCharacteristics;
4322 Sii->Machine = ImageSectionObject->Machine;
4323 Sii->ImageContainsCode = ImageSectionObject->Executable;
4324 }
4325
4326 if (ResultLength != NULL)
4327 {
4328 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
4329 }
4330 Status = STATUS_SUCCESS;
4331 }
4332 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4333 {
4334 Status = _SEH2_GetExceptionCode();
4335 }
4336 _SEH2_END;
4337
4338 break;
4339 }
4340 }
4341
4342 ObDereferenceObject(Section);
4343 }
4344
4345 return(Status);
4346 }
4347
4348
4349 /**
4350 * Extends size of file backed section.
4351 *
4352 * @param SectionHandle
4353 * Handle to the section object. It must be opened with
4354 * SECTION_EXTEND_SIZE access.
4355 * @param NewMaximumSize
4356 * New maximum size of the section in bytes.
4357 *
4358 * @return Status.
4359 *
4360 * @todo Move the actual code to internal function MmExtendSection.
4361 * @unimplemented
4362 */
4363 NTSTATUS NTAPI
4364 NtExtendSection(IN HANDLE SectionHandle,
4365 IN PLARGE_INTEGER NewMaximumSize)
4366 {
4367 LARGE_INTEGER SafeNewMaximumSize;
4368 PROS_SECTION_OBJECT Section;
4369 KPROCESSOR_MODE PreviousMode;
4370 NTSTATUS Status;
4371
4372 PreviousMode = ExGetPreviousMode();
4373
4374 if(PreviousMode != KernelMode)
4375 {
4376 _SEH2_TRY
4377 {
4378 /* make a copy on the stack */
4379 SafeNewMaximumSize = ProbeForReadLargeInteger(NewMaximumSize);
4380 NewMaximumSize = &SafeNewMaximumSize;
4381 }
4382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4383 {
4384 /* Return the exception code */
4385 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4386 }
4387 _SEH2_END;
4388 }
4389
4390 Status = ObReferenceObjectByHandle(SectionHandle,
4391 SECTION_EXTEND_SIZE,
4392 MmSectionObjectType,
4393 PreviousMode,
4394 (PVOID*)&Section,
4395 NULL);
4396 if (!NT_SUCCESS(Status))
4397 {
4398 return Status;
4399 }
4400
4401 if (!(Section->AllocationAttributes & SEC_FILE))
4402 {
4403 ObDereferenceObject(Section);
4404 return STATUS_INVALID_PARAMETER;
4405 }
4406
4407 /*
4408 * - Acquire file extneding resource.
4409 * - Check if we're not resizing the section below it's actual size!
4410 * - Extend segments if needed.
4411 * - Set file information (FileAllocationInformation) to the new size.
4412 * - Release file extending resource.
4413 */
4414
4415 ObDereferenceObject(Section);
4416
4417 return STATUS_NOT_IMPLEMENTED;
4418 }
4419
4420 /**********************************************************************
4421 * NAME EXPORTED
4422 * MmMapViewOfSection
4423 *
4424 * DESCRIPTION
4425 * Maps a view of a section into the virtual address space of a
4426 * process.
4427 *
4428 * ARGUMENTS
4429 * Section
4430 * Pointer to the section object.
4431 *
4432 * ProcessHandle
4433 * Pointer to the process.
4434 *
4435 * BaseAddress
4436 * Desired base address (or NULL) on entry;
4437 * Actual base address of the view on exit.
4438 *
4439 * ZeroBits
4440 * Number of high order address bits that must be zero.
4441 *
4442 * CommitSize
4443 * Size in bytes of the initially committed section of
4444 * the view.
4445 *
4446 * SectionOffset
4447 * Offset in bytes from the beginning of the section
4448 * to the beginning of the view.
4449 *
4450 * ViewSize
4451 * Desired length of map (or zero to map all) on entry
4452 * Actual length mapped on exit.
4453 *
4454 * InheritDisposition
4455 * Specified how the view is to be shared with
4456 * child processes.
4457 *
4458 * AllocationType
4459 * Type of allocation for the pages.
4460 *
4461 * Protect
4462 * Protection for the committed region of the view.
4463 *
4464 * RETURN VALUE
4465 * Status.
4466 *
4467 * @implemented
4468 */
4469 NTSTATUS NTAPI
4470 MmMapViewOfSection(IN PVOID SectionObject,
4471 IN PEPROCESS Process,
4472 IN OUT PVOID *BaseAddress,
4473 IN ULONG_PTR ZeroBits,
4474 IN SIZE_T CommitSize,
4475 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
4476 IN OUT PSIZE_T ViewSize,
4477 IN SECTION_INHERIT InheritDisposition,
4478 IN ULONG AllocationType,
4479 IN ULONG Protect)
4480 {
4481 PROS_SECTION_OBJECT Section;
4482 PMMSUPPORT AddressSpace;
4483 ULONG ViewOffset;
4484 NTSTATUS Status = STATUS_SUCCESS;
4485
4486 ASSERT(Process);
4487
4488 if (!Protect || Protect & ~PAGE_FLAGS_VALID_FOR_SECTION)
4489 {
4490 return STATUS_INVALID_PAGE_PROTECTION;
4491 }
4492
4493
4494 Section = (PROS_SECTION_OBJECT)SectionObject;
4495 AddressSpace = &Process->Vm;
4496
4497 AllocationType |= (Section->AllocationAttributes & SEC_NO_CHANGE);
4498
4499 MmLockAddressSpace(AddressSpace);
4500
4501 if (Section->AllocationAttributes & SEC_IMAGE)
4502 {
4503 ULONG i;
4504 ULONG NrSegments;
4505 ULONG_PTR ImageBase;
4506 ULONG ImageSize;
4507 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
4508 PMM_SECTION_SEGMENT SectionSegments;
4509
4510 ImageSectionObject = Section->ImageSection;
4511 SectionSegments = ImageSectionObject->Segments;
4512 NrSegments = ImageSectionObject->NrSegments;
4513
4514
4515 ImageBase = (ULONG_PTR)*BaseAddress;
4516 if (ImageBase == 0)
4517 {
4518 ImageBase = ImageSectionObject->ImageBase;
4519 }
4520
4521 ImageSize = 0;
4522 for (i = 0; i < NrSegments; i++)
4523 {
4524 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4525 {
4526 ULONG_PTR MaxExtent;
4527 MaxExtent = (ULONG_PTR)SectionSegments[i].VirtualAddress +
4528 SectionSegments[i].Length;
4529 ImageSize = max(ImageSize, MaxExtent);
4530 }
4531 }
4532
4533 ImageSectionObject->ImageSize = ImageSize;
4534
4535 /* Check there is enough space to map the section at that point. */
4536 if (MmLocateMemoryAreaByRegion(AddressSpace, (PVOID)ImageBase,
4537 PAGE_ROUND_UP(ImageSize)) != NULL)
4538 {
4539 /* Fail if the user requested a fixed base address. */
4540 if ((*BaseAddress) != NULL)
4541 {
4542 MmUnlockAddressSpace(AddressSpace);
4543 return(STATUS_UNSUCCESSFUL);
4544 }
4545 /* Otherwise find a gap to map the image. */
4546 ImageBase = (ULONG_PTR)MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), PAGE_SIZE, FALSE);
4547 if (ImageBase == 0)
4548 {
4549 MmUnlockAddressSpace(AddressSpace);
4550 return(STATUS_UNSUCCESSFUL);
4551 }
4552 }
4553
4554 for (i = 0; i < NrSegments; i++)
4555 {
4556 if (!(SectionSegments[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
4557 {
4558 PVOID SBaseAddress = (PVOID)
4559 ((char*)ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
4560 MmLockSectionSegment(&SectionSegments[i]);
4561 Status = MmMapViewOfSegment(AddressSpace,
4562 Section,
4563 &SectionSegments[i],
4564 &SBaseAddress,
4565 SectionSegments[i].Length,
4566 SectionSegments[i].Protection,
4567 0,
4568 0);
4569 MmUnlockSectionSegment(&SectionSegments[i]);
4570 if (!NT_SUCCESS(Status))
4571 {
4572 MmUnlockAddressSpace(AddressSpace);
4573 return(Status);
4574 }
4575 }
4576 }
4577
4578 *BaseAddress = (PVOID)ImageBase;
4579 }
4580 else
4581 {
4582 /* check for write access */
4583 if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) &&
4584 !(Section->SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)))
4585 {
4586 MmUnlockAddressSpace(AddressSpace);
4587 return STATUS_SECTION_PROTECTION;
4588 }
4589 /* check for read access */
4590 if ((Protect & (PAGE_READONLY|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_WRITECOPY)) &&
4591 !(Section->SectionPageProtection & (PAGE_READONLY|PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4592 {
4593 MmUnlockAddressSpace(AddressSpace);
4594 return STATUS_SECTION_PROTECTION;
4595 }
4596 /* check for execute access */
4597 if ((Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) &&
4598 !(Section->SectionPageProtection & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)))
4599 {
4600 MmUnlockAddressSpace(AddressSpace);
4601 return STATUS_SECTION_PROTECTION;
4602 }
4603
4604 if (ViewSize == NULL)
4605 {
4606 /* Following this pointer would lead to us to the dark side */
4607 /* What to do? Bugcheck? Return status? Do the mambo? */
4608 KeBugCheck(MEMORY_MANAGEMENT);
4609 }
4610
4611 if (SectionOffset == NULL)
4612 {
4613 ViewOffset = 0;
4614 }
4615 else
4616 {
4617 ViewOffset = SectionOffset->u.LowPart;
4618 }
4619
4620 if ((ViewOffset % PAGE_SIZE) != 0)
4621 {
4622 MmUnlockAddressSpace(AddressSpace);
4623 return(STATUS_MAPPED_ALIGNMENT);
4624 }
4625
4626 if ((*ViewSize) == 0)
4627 {
4628 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4629 }
4630 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
4631 {
4632 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
4633 }
4634
4635 *ViewSize = PAGE_ROUND_UP(*ViewSize);
4636
4637 MmLockSectionSegment(Section->Segment);
4638 Status = MmMapViewOfSegment(AddressSpace,
4639 Section,
4640 Section->Segment,
4641 BaseAddress,
4642 *ViewSize,
4643 Protect,
4644 ViewOffset,
4645 AllocationType & (MEM_TOP_DOWN|SEC_NO_CHANGE));
4646 MmUnlockSectionSegment(Section->Segment);
4647 if (!NT_SUCCESS(Status))
4648 {
4649 MmUnlockAddressSpace(AddressSpace);
4650 return(Status);
4651 }
4652 }
4653
4654 MmUnlockAddressSpace(AddressSpace);
4655
4656 return(STATUS_SUCCESS);
4657 }
4658
4659 /*
4660 * @unimplemented
4661 */
4662 BOOLEAN NTAPI
4663 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4664 IN PLARGE_INTEGER NewFileSize)
4665 {
4666 /* Check whether an ImageSectionObject exists */
4667 if (SectionObjectPointer->ImageSectionObject != NULL)
4668 {
4669 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4670 return FALSE;
4671 }
4672
4673 if (SectionObjectPointer->DataSectionObject != NULL)
4674 {
4675 PMM_SECTION_SEGMENT Segment;
4676
4677 Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->
4678 DataSectionObject;
4679
4680 if (Segment->ReferenceCount != 0)
4681 {
4682 /* Check size of file */
4683 if (SectionObjectPointer->SharedCacheMap)
4684 {
4685 PBCB Bcb = SectionObjectPointer->SharedCacheMap;
4686 if (NewFileSize->QuadPart <= Bcb->FileSize.QuadPart)
4687 {
4688 return FALSE;
4689 }
4690 }
4691 }
4692 else
4693 {
4694 /* Something must gone wrong
4695 * how can we have a Section but no
4696 * reference? */
4697 DPRINT("ERROR: DataSectionObject without reference!\n");
4698 }
4699 }
4700
4701 DPRINT("FIXME: didn't check for outstanding write probes\n");
4702
4703 return TRUE;
4704 }
4705
4706
4707 /*
4708 * @unimplemented
4709 */
4710 BOOLEAN NTAPI
4711 MmDisableModifiedWriteOfSection (ULONG Unknown0)
4712 {
4713 UNIMPLEMENTED;
4714 return (FALSE);
4715 }
4716
4717 /*
4718 * @implemented
4719 */
4720 BOOLEAN NTAPI
4721 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4722 IN MMFLUSH_TYPE FlushType)
4723 {
4724 switch(FlushType)
4725 {
4726 case MmFlushForDelete:
4727 if (SectionObjectPointer->ImageSectionObject ||
4728 SectionObjectPointer->DataSectionObject)
4729 {
4730 return FALSE;
4731 }
4732 CcRosSetRemoveOnClose(SectionObjectPointer);
4733 return TRUE;
4734 case MmFlushForWrite:
4735 break;
4736 }
4737 return FALSE;
4738 }
4739
4740 /*
4741 * @unimplemented
4742 */
4743 BOOLEAN NTAPI
4744 MmForceSectionClosed (
4745 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
4746 IN BOOLEAN DelayClose)
4747 {
4748 UNIMPLEMENTED;
4749 return (FALSE);
4750 }
4751
4752
4753 /*
4754 * @implemented
4755 */
4756 NTSTATUS NTAPI
4757 MmMapViewInSystemSpace (IN PVOID SectionObject,
4758 OUT PVOID * MappedBase,
4759 IN OUT PSIZE_T ViewSize)
4760 {
4761 PROS_SECTION_OBJECT Section;
4762 PMMSUPPORT AddressSpace;
4763 NTSTATUS Status;
4764
4765 DPRINT("MmMapViewInSystemSpace() called\n");
4766
4767 Section = (PROS_SECTION_OBJECT)SectionObject;
4768 AddressSpace = MmGetKernelAddressSpace();
4769
4770 MmLockAddressSpace(AddressSpace);
4771
4772
4773 if ((*ViewSize) == 0)
4774 {
4775 (*ViewSize) = Section->MaximumSize.u.LowPart;
4776 }
4777 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
4778 {
4779 (*ViewSize) = Section->MaximumSize.u.LowPart;
4780 }
4781
4782 MmLockSectionSegment(Section->Segment);
4783
4784
4785 Status = MmMapViewOfSegment(AddressSpace,
4786 Section,
4787 Section->Segment,
4788 MappedBase,
4789 *ViewSize,
4790 PAGE_READWRITE,
4791 0,
4792 0);
4793
4794 MmUnlockSectionSegment(Section->Segment);
4795 MmUnlockAddressSpace(AddressSpace);
4796
4797 return Status;
4798 }
4799
4800 /*
4801 * @unimplemented
4802 */
4803 NTSTATUS
4804 NTAPI
4805 MmMapViewInSessionSpace (
4806 IN PVOID Section,
4807 OUT PVOID *MappedBase,
4808 IN OUT PSIZE_T ViewSize
4809 )
4810 {
4811 UNIMPLEMENTED;
4812 return STATUS_NOT_IMPLEMENTED;
4813 }
4814
4815
4816 /*
4817 * @implemented
4818 */
4819 NTSTATUS NTAPI
4820 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
4821 {
4822 PMMSUPPORT AddressSpace;
4823 NTSTATUS Status;
4824
4825 DPRINT("MmUnmapViewInSystemSpace() called\n");
4826
4827 AddressSpace = MmGetKernelAddressSpace();
4828
4829 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
4830
4831 return Status;
4832 }
4833
4834 /*
4835 * @unimplemented
4836 */
4837 NTSTATUS
4838 NTAPI
4839 MmUnmapViewInSessionSpace (
4840 IN PVOID MappedBase
4841 )
4842 {
4843 UNIMPLEMENTED;
4844 return STATUS_NOT_IMPLEMENTED;
4845 }
4846
4847 /**********************************************************************
4848 * NAME EXPORTED
4849 * MmCreateSection@
4850 *
4851 * DESCRIPTION
4852 * Creates a section object.
4853 *
4854 * ARGUMENTS
4855 * SectionObject (OUT)
4856 * Caller supplied storage for the resulting pointer
4857 * to a SECTION_OBJECT instance;
4858 *
4859 * DesiredAccess
4860 * Specifies the desired access to the section can be a
4861 * combination of:
4862 * STANDARD_RIGHTS_REQUIRED |
4863 * SECTION_QUERY |
4864 * SECTION_MAP_WRITE |
4865 * SECTION_MAP_READ |
4866 * SECTION_MAP_EXECUTE
4867 *
4868 * ObjectAttributes [OPTIONAL]
4869 * Initialized attributes for the object can be used
4870 * to create a named section;
4871 *
4872 * MaximumSize
4873 * Maximizes the size of the memory section. Must be
4874 * non-NULL for a page-file backed section.
4875 * If value specified for a mapped file and the file is
4876 * not large enough, file will be extended.
4877 *
4878 * SectionPageProtection
4879 * Can be a combination of:
4880 * PAGE_READONLY |
4881 * PAGE_READWRITE |
4882 * PAGE_WRITEONLY |
4883 * PAGE_WRITECOPY
4884 *
4885 * AllocationAttributes
4886 * Can be a combination of:
4887 * SEC_IMAGE |
4888 * SEC_RESERVE
4889 *
4890 * FileHandle
4891 * Handle to a file to create a section mapped to a file
4892 * instead of a memory backed section;
4893 *
4894 * File
4895 * Unknown.
4896 *
4897 * RETURN VALUE
4898 * Status.
4899 *
4900 * @implemented
4901 */
4902 NTSTATUS NTAPI
4903 MmCreateSection (OUT PVOID * Section,
4904 IN ACCESS_MASK DesiredAccess,
4905 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4906 IN PLARGE_INTEGER MaximumSize,
4907 IN ULONG SectionPageProtection,
4908 IN ULONG AllocationAttributes,
4909 IN HANDLE FileHandle OPTIONAL,
4910 IN PFILE_OBJECT File OPTIONAL)
4911 {
4912 ULONG Protection;
4913 PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
4914
4915 /*
4916 * Check the protection
4917 */
4918 Protection = SectionPageProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
4919 if (Protection != PAGE_READONLY &&
4920 Protection != PAGE_READWRITE &&
4921 Protection != PAGE_WRITECOPY &&
4922 Protection != PAGE_EXECUTE &&
4923 Protection != PAGE_EXECUTE_READ &&
4924 Protection != PAGE_EXECUTE_READWRITE &&
4925 Protection != PAGE_EXECUTE_WRITECOPY)
4926 {
4927 return STATUS_INVALID_PAGE_PROTECTION;
4928 }
4929
4930 if (AllocationAttributes & SEC_IMAGE)
4931 {
4932 return(MmCreateImageSection(SectionObject,
4933 DesiredAccess,
4934 ObjectAttributes,
4935 MaximumSize,
4936 SectionPageProtection,
4937 AllocationAttributes,
4938 FileHandle));
4939 }
4940
4941 if (FileHandle != NULL)
4942 {
4943 return(MmCreateDataFileSection(SectionObject,
4944 DesiredAccess,
4945 ObjectAttributes,
4946 MaximumSize,
4947 SectionPageProtection,
4948 AllocationAttributes,
4949 FileHandle));
4950 }
4951
4952 return(MmCreatePageFileSection(SectionObject,
4953 DesiredAccess,
4954 ObjectAttributes,
4955 MaximumSize,
4956 SectionPageProtection,
4957 AllocationAttributes));
4958 }
4959
4960 NTSTATUS
4961 NTAPI
4962 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
4963 IN PVOID File2MappedAsFile)
4964 {
4965 UNIMPLEMENTED;
4966 return STATUS_NOT_IMPLEMENTED;
4967 }
4968
4969
4970 /* EOF */