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