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