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