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