finished applying @implemented and @unimplemented comments and remove the comments...
[reactos.git] / reactos / ntoskrnl / mm / section.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: section.c,v 1.121 2003/07/11 01:23:15 royce Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/section.c
23 * PURPOSE: Implements section objects
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * Created 22/05/98
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <limits.h>
32 #define NTOS_MODE_KERNEL
33 #include <ntos.h>
34 #include <internal/mm.h>
35 #include <internal/io.h>
36 #include <internal/ps.h>
37 #include <internal/pool.h>
38 #include <internal/cc.h>
39 #include <ddk/ntifs.h>
40 #include <ntos/minmax.h>
41
42 #define NDEBUG
43 #include <internal/debug.h>
44
45 /* TYPES *********************************************************************/
46
47 typedef struct
48 {
49 PSECTION_OBJECT Section;
50 PMM_SECTION_SEGMENT Segment;
51 ULONG Offset;
52 BOOLEAN WasDirty;
53 BOOLEAN Private;
54 } MM_SECTION_PAGEOUT_CONTEXT;
55
56 /* GLOBALS *******************************************************************/
57
58 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
59
60 static GENERIC_MAPPING MmpSectionMapping = {
61 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
62 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
63 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
64 SECTION_ALL_ACCESS};
65
66 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
67 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
68
69 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
70 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
71 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
72 #define MAX_SHARE_COUNT 0x7FF
73 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
74 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
75 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
76
77 /* FUNCTIONS *****************************************************************/
78
79 VOID
80 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
81 {
82 ULONG i;
83 if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
84 {
85 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
86 {
87 if (Segment->PageDirectory.PageTables[i] != NULL)
88 {
89 ExFreePool(Segment->PageDirectory.PageTables[i]);
90 }
91 }
92 }
93 }
94
95 VOID
96 MmFreeSectionSegments(PFILE_OBJECT FileObject)
97 {
98 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
99 {
100 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
101 PMM_SECTION_SEGMENT SectionSegments;
102 ULONG NrSegments;
103 ULONG i;
104
105 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
106 NrSegments = ImageSectionObject->NrSegments;
107 SectionSegments = ImageSectionObject->Segments;
108 for (i = 0; i < NrSegments; i++)
109 {
110 if (SectionSegments[i].ReferenceCount != 0)
111 {
112 DPRINT1("Image segment %d still referenced (was %d)\n", i,
113 SectionSegments[i].ReferenceCount);
114 KeBugCheck(0);
115 }
116 MmFreePageTablesSectionSegment(&SectionSegments[i]);
117 }
118 ExFreePool(ImageSectionObject);
119 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
120 }
121 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
122 {
123 PMM_SECTION_SEGMENT Segment;
124
125 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
126 DataSectionObject;
127
128 if (Segment->ReferenceCount != 0)
129 {
130 DPRINT1("Data segment still referenced\n");
131 KeBugCheck(0);
132 }
133 MmFreePageTablesSectionSegment(Segment);
134 ExFreePool(Segment);
135 FileObject->SectionObjectPointer->DataSectionObject = NULL;
136 }
137 }
138
139 VOID
140 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
141 {
142 ExAcquireFastMutex(&Segment->Lock);
143 }
144
145 VOID
146 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
147 {
148 ExReleaseFastMutex(&Segment->Lock);
149 }
150
151 VOID
152 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
153 ULONG Offset,
154 ULONG Entry)
155 {
156 PSECTION_PAGE_TABLE Table;
157 ULONG DirectoryOffset;
158 ULONG TableOffset;
159
160 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
161 {
162 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
163 }
164 else
165 {
166 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
167 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
168 if (Table == NULL)
169 {
170 Table =
171 Segment->PageDirectory.PageTables[DirectoryOffset] =
172 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
173 TAG_SECTION_PAGE_TABLE);
174 if (Table == NULL)
175 {
176 KeBugCheck(0);
177 }
178 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
179 DPRINT("Table %x\n", Table);
180 }
181 }
182 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
183 Table->Entry[TableOffset] = Entry;
184 }
185
186
187 ULONG
188 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
189 ULONG Offset)
190 {
191 PSECTION_PAGE_TABLE Table;
192 ULONG Entry;
193 ULONG DirectoryOffset;
194 ULONG TableOffset;
195
196 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
197
198 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
199 {
200 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
201 }
202 else
203 {
204 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
205 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
206 DPRINT("Table %x\n", Table);
207 if (Table == NULL)
208 {
209 return(0);
210 }
211 }
212 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
213 Entry = Table->Entry[TableOffset];
214 return(Entry);
215 }
216
217 VOID
218 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
219 ULONG Offset)
220 {
221 ULONG Entry;
222
223 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
224 if (Entry == 0)
225 {
226 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
227 KeBugCheck(0);
228 }
229 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
230 {
231 DPRINT1("Maximum share count reached\n");
232 KeBugCheck(0);
233 }
234 if (IS_SWAP_FROM_SSE(Entry))
235 {
236 KeBugCheck(0);
237 }
238 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
239 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
240 }
241
242 BOOLEAN
243 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
244 PMM_SECTION_SEGMENT Segment,
245 ULONG Offset,
246 BOOLEAN Dirty)
247 {
248 ULONG Entry;
249
250 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
251 if (Entry == 0)
252 {
253 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
254 KeBugCheck(0);
255 }
256 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
257 {
258 DPRINT1("Zero share count for unshare\n");
259 KeBugCheck(0);
260 }
261 if (IS_SWAP_FROM_SSE(Entry))
262 {
263 KeBugCheck(0);
264 }
265 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
266 /*
267 * If we reducing the share count of this entry to zero then set the entry
268 * to zero and tell the cache the page is no longer mapped.
269 */
270 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
271 {
272 PFILE_OBJECT FileObject;
273 PBCB Bcb;
274 SWAPENTRY SavedSwapEntry;
275 PHYSICAL_ADDRESS Page;
276 BOOLEAN IsImageSection;
277 ULONG FileOffset;
278
279 FileOffset = Offset + Segment->FileOffset;
280
281 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
282
283 MmSetPageEntrySectionSegment(Segment, Offset, 0);
284 Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
285 FileObject = Section->FileObject;
286 if (FileObject != NULL)
287 {
288
289 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
290 (FileOffset % PAGE_SIZE) == 0 &&
291 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
292 {
293 NTSTATUS Status;
294 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
295 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
296 if (!NT_SUCCESS(Status))
297 {
298 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
299 KeBugCheck(0);
300 }
301 }
302 }
303
304 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
305 if (SavedSwapEntry != 0)
306 {
307 MmFreeSwapPage(SavedSwapEntry);
308 MmSetSavedSwapEntryPage(Page, 0);
309 }
310 }
311 else
312 {
313 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
314 }
315 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
316 }
317
318 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
319 ULONG SegOffset)
320 {
321 PBCB Bcb;
322 PCACHE_SEGMENT CacheSeg;
323
324 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
325 CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
326 if (CacheSeg)
327 {
328 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
329 return TRUE;
330 }
331 return FALSE;
332 }
333
334 NTSTATUS
335 MiReadPage(PMEMORY_AREA MemoryArea,
336 ULONG SegOffset,
337 PHYSICAL_ADDRESS* Page)
338 /*
339 * FUNCTION: Read a page for a section backed memory area.
340 * PARAMETERS:
341 * MemoryArea - Memory area to read the page for.
342 * Offset - Offset of the page to read.
343 * Page - Variable that receives a page contains the read data.
344 */
345 {
346 ULONG BaseOffset;
347 ULONG FileOffset;
348 PVOID BaseAddress;
349 BOOLEAN UptoDate;
350 PCACHE_SEGMENT CacheSeg;
351 PFILE_OBJECT FileObject;
352 NTSTATUS Status;
353 ULONG RawLength;
354 PBCB Bcb;
355 BOOLEAN IsImageSection;
356 ULONG Length;
357
358 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
359 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
360 RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
361 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
362 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
363
364 assert(Bcb);
365
366 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
367
368 /*
369 * If the file system is letting us go directly to the cache and the
370 * memory area was mapped at an offset in the file which is page aligned
371 * then get the related cache segment.
372 */
373 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
374 (FileOffset % PAGE_SIZE) == 0 &&
375 (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection))
376 {
377 PHYSICAL_ADDRESS Addr;
378
379 /*
380 * Get the related cache segment; we use a lower level interface than
381 * filesystems do because it is safe for us to use an offset with a
382 * alignment less than the file system block size.
383 */
384 Status = CcRosGetCacheSegment(Bcb,
385 FileOffset,
386 &BaseOffset,
387 &BaseAddress,
388 &UptoDate,
389 &CacheSeg);
390 if (!NT_SUCCESS(Status))
391 {
392 return(Status);
393 }
394 if (!UptoDate)
395 {
396 /*
397 * If the cache segment isn't up to date then call the file
398 * system to read in the data.
399 */
400 Status = ReadCacheSegment(CacheSeg);
401 if (!NT_SUCCESS(Status))
402 {
403 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
404 return Status;
405 }
406 }
407 /*
408 * Retrieve the page from the cache segment that we actually want.
409 */
410 Addr = MmGetPhysicalAddress(BaseAddress +
411 FileOffset - BaseOffset);
412 (*Page) = Addr;
413 MmReferencePage((*Page));
414
415 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
416 }
417 else
418 {
419 PVOID PageAddr;
420 ULONG CacheSegOffset;
421 /*
422 * Allocate a page, this is rather complicated by the possibility
423 * we might have to move other things out of memory
424 */
425 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
426 if (!NT_SUCCESS(Status))
427 {
428 return(Status);
429 }
430 Status = CcRosGetCacheSegment(Bcb,
431 FileOffset,
432 &BaseOffset,
433 &BaseAddress,
434 &UptoDate,
435 &CacheSeg);
436 if (!NT_SUCCESS(Status))
437 {
438 return(Status);
439 }
440 if (!UptoDate)
441 {
442 /*
443 * If the cache segment isn't up to date then call the file
444 * system to read in the data.
445 */
446 Status = ReadCacheSegment(CacheSeg);
447 if (!NT_SUCCESS(Status))
448 {
449 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
450 return Status;
451 }
452 }
453 PageAddr = ExAllocatePageWithPhysPage(*Page);
454 CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
455 Length = RawLength - SegOffset;
456 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
457 {
458 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, Length);
459 }
460 else if (CacheSegOffset >= PAGE_SIZE)
461 {
462 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
463 }
464 else
465 {
466 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
467 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
468 Status = CcRosGetCacheSegment(Bcb,
469 FileOffset + CacheSegOffset,
470 &BaseOffset,
471 &BaseAddress,
472 &UptoDate,
473 &CacheSeg);
474 if (!NT_SUCCESS(Status))
475 {
476 ExUnmapPage(PageAddr);
477 return(Status);
478 }
479 if (!UptoDate)
480 {
481 /*
482 * If the cache segment isn't up to date then call the file
483 * system to read in the data.
484 */
485 Status = ReadCacheSegment(CacheSeg);
486 if (!NT_SUCCESS(Status))
487 {
488 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
489 ExUnmapPage(PageAddr);
490 return Status;
491 }
492 }
493 if (Length < PAGE_SIZE)
494 {
495 memcpy(PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
496 }
497 else
498 {
499 memcpy(PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
500 }
501 }
502 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
503 ExUnmapPage(PageAddr);
504 }
505 return(STATUS_SUCCESS);
506 }
507
508 NTSTATUS
509 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
510 MEMORY_AREA* MemoryArea,
511 PVOID Address,
512 BOOLEAN Locked)
513 {
514 ULONG Offset;
515 LARGE_INTEGER Page;
516 NTSTATUS Status;
517 ULONG PAddress;
518 PSECTION_OBJECT Section;
519 PMM_SECTION_SEGMENT Segment;
520 ULONG Entry;
521 ULONG Entry1;
522 ULONG Attributes;
523 PMM_PAGEOP PageOp;
524 PMM_REGION Region;
525 LARGE_INTEGER Timeout;
526
527 /*
528 * There is a window between taking the page fault and locking the
529 * address space when another thread could load the page so we check
530 * that.
531 */
532 if (MmIsPagePresent(AddressSpace->Process, Address))
533 {
534 if (Locked)
535 {
536 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address));
537 }
538 return(STATUS_SUCCESS);
539 }
540
541 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
542 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
543
544 Segment = MemoryArea->Data.SectionData.Segment;
545 Section = MemoryArea->Data.SectionData.Section;
546 Region = MmFindRegion(MemoryArea->BaseAddress,
547 &MemoryArea->Data.SectionData.RegionListHead,
548 Address, NULL);
549 /*
550 * Lock the segment
551 */
552 MmLockSectionSegment(Segment);
553
554 /*
555 * Check if this page needs to be mapped COW
556 */
557 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
558 (Region->Protect == PAGE_READWRITE ||
559 Region->Protect == PAGE_EXECUTE_READWRITE))
560 {
561 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
562 }
563 else
564 {
565 Attributes = Region->Protect;
566 }
567
568 /*
569 * Get or create a page operation descriptor
570 */
571 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN);
572 if (PageOp == NULL)
573 {
574 DPRINT1("MmGetPageOp failed\n");
575 KeBugCheck(0);
576 }
577
578 /*
579 * Check if someone else is already handling this fault, if so wait
580 * for them
581 */
582 if (PageOp->Thread != PsGetCurrentThread())
583 {
584 MmUnlockSectionSegment(Segment);
585 MmUnlockAddressSpace(AddressSpace);
586 Timeout.QuadPart = -100000000LL; // 10 sec
587 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
588 0,
589 KernelMode,
590 FALSE,
591 &Timeout);
592
593 /*
594 * Check for various strange conditions
595 */
596 if (Status != STATUS_SUCCESS)
597 {
598 DPRINT1("Failed to wait for page op, status = %x\n", Status);
599 KeBugCheck(0);
600 }
601 if (PageOp->Status == STATUS_PENDING)
602 {
603 DPRINT1("Woke for page op before completion\n");
604 KeBugCheck(0);
605 }
606 MmLockAddressSpace(AddressSpace);
607 /*
608 * If this wasn't a pagein then restart the operation
609 */
610 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
611 {
612 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
613 MmReleasePageOp(PageOp);
614 DPRINT("Address 0x%.8X\n", Address);
615 return(STATUS_MM_RESTART_OPERATION);
616 }
617
618 /*
619 * If the thread handling this fault has failed then we don't retry
620 */
621 if (!NT_SUCCESS(PageOp->Status))
622 {
623 Status = PageOp->Status;
624 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
625 MmReleasePageOp(PageOp);
626 DPRINT("Address 0x%.8X\n", Address);
627 return(Status);
628 }
629 MmLockSectionSegment(Segment);
630 /*
631 * If the completed fault was for another address space then set the
632 * page in this one.
633 */
634 if (!MmIsPagePresent(AddressSpace->Process, Address))
635 {
636 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
637 if (Entry == 0)
638 {
639 MmUnlockSectionSegment(Segment);
640 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
641 MmReleasePageOp(PageOp);
642 return(STATUS_MM_RESTART_OPERATION);
643 }
644
645 Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
646 MmReferencePage(Page);
647 MmSharePageEntrySectionSegment(Segment, Offset);
648
649 Status = MmCreateVirtualMapping(MemoryArea->Process,
650 Address,
651 Attributes,
652 Page,
653 FALSE);
654 if (Status == STATUS_NO_MEMORY)
655 {
656 MmUnlockAddressSpace(AddressSpace);
657 Status = MmCreateVirtualMapping(MemoryArea->Process,
658 Address,
659 Attributes,
660 Page,
661 TRUE);
662 MmLockAddressSpace(AddressSpace);
663 }
664
665 if (!NT_SUCCESS(Status))
666 {
667 DbgPrint("Unable to create virtual mapping\n");
668 KeBugCheck(0);
669 }
670 MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
671 }
672 if (Locked)
673 {
674 MmLockPage(Page);
675 }
676 MmUnlockSectionSegment(Segment);
677 PageOp->Status = STATUS_SUCCESS;
678 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
679 MmReleasePageOp(PageOp);
680 DPRINT("Address 0x%.8X\n", Address);
681 return(STATUS_SUCCESS);
682 }
683
684 /*
685 * Must be private page we have swapped out.
686 */
687 if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress))
688 {
689 SWAPENTRY SwapEntry;
690 PMDL Mdl;
691
692 MmUnlockSectionSegment(Segment);
693 MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
694
695 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
696 if (!NT_SUCCESS(Status))
697 {
698 KeBugCheck(0);
699 }
700
701 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
702 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
703 MmUnlockAddressSpace(AddressSpace);
704 Status = MmReadFromSwapPage(SwapEntry, Mdl);
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
708 KeBugCheck(0);
709 }
710 MmLockAddressSpace(AddressSpace);
711 Status = MmCreateVirtualMapping(AddressSpace->Process,
712 Address,
713 Region->Protect,
714 Page,
715 FALSE);
716 if (Status == STATUS_NO_MEMORY)
717 {
718 MmUnlockAddressSpace(AddressSpace);
719 Status = MmCreateVirtualMapping(AddressSpace->Process,
720 Address,
721 Region->Protect,
722 Page,
723 TRUE);
724 MmLockAddressSpace(AddressSpace);
725 }
726 if (!NT_SUCCESS(Status))
727 {
728 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
729 KeBugCheck(0);
730 return(Status);
731 }
732
733 /*
734 * Store the swap entry for later use.
735 */
736 MmSetSavedSwapEntryPage(Page, SwapEntry);
737
738 /*
739 * Add the page to the process's working set
740 */
741 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
742
743 /*
744 * Finish the operation
745 */
746 if (Locked)
747 {
748 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
749 }
750 PageOp->Status = STATUS_SUCCESS;
751 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
752 MmReleasePageOp(PageOp);
753 DPRINT("Address 0x%.8X\n", Address);
754 return(STATUS_SUCCESS);
755 }
756
757 /*
758 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
759 */
760 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
761 {
762 MmUnlockSectionSegment(Segment);
763 /*
764 * Just map the desired physical page
765 */
766 Page.QuadPart = Offset + MemoryArea->Data.SectionData.ViewOffset;
767 Status = MmCreateVirtualMapping(AddressSpace->Process,
768 Address,
769 Region->Protect,
770 Page,
771 FALSE);
772 if (Status == STATUS_NO_MEMORY)
773 {
774 MmUnlockAddressSpace(AddressSpace);
775 Status = MmCreateVirtualMapping(AddressSpace->Process,
776 Address,
777 Region->Protect,
778 Page,
779 TRUE);
780 MmLockAddressSpace(AddressSpace);
781 }
782 if (!NT_SUCCESS(Status))
783 {
784 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
785 KeBugCheck(0);
786 return(Status);
787 }
788 /*
789 * Don't add an rmap entry since the page mapped could be for
790 * anything.
791 */
792 if (Locked)
793 {
794 MmLockPage(Page);
795 }
796
797 /*
798 * Cleanup and release locks
799 */
800 PageOp->Status = STATUS_SUCCESS;
801 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
802 MmReleasePageOp(PageOp);
803 DPRINT("Address 0x%.8X\n", Address);
804 return(STATUS_SUCCESS);
805 }
806
807 /*
808 * Map anonymous memory for BSS sections
809 */
810 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
811 {
812 MmUnlockSectionSegment(Segment);
813 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
814 if (!NT_SUCCESS(Status))
815 {
816 MmUnlockAddressSpace(AddressSpace);
817 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
818 MmLockAddressSpace(AddressSpace);
819 }
820 if (!NT_SUCCESS(Status))
821 {
822 KeBugCheck(0);
823 }
824 Status = MmCreateVirtualMapping(AddressSpace->Process,
825 Address,
826 Region->Protect,
827 Page,
828 FALSE);
829 if (Status == STATUS_NO_MEMORY)
830 {
831 MmUnlockAddressSpace(AddressSpace);
832 Status = MmCreateVirtualMapping(AddressSpace->Process,
833 Address,
834 Region->Protect,
835 Page,
836 TRUE);
837 MmLockAddressSpace(AddressSpace);
838 }
839
840 if (!NT_SUCCESS(Status))
841 {
842 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
843 KeBugCheck(0);
844 return(Status);
845 }
846 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
847 if (Locked)
848 {
849 MmLockPage(Page);
850 }
851
852 /*
853 * Cleanup and release locks
854 */
855 PageOp->Status = STATUS_SUCCESS;
856 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
857 MmReleasePageOp(PageOp);
858 DPRINT("Address 0x%.8X\n", Address);
859 return(STATUS_SUCCESS);
860 }
861
862 /*
863 * Get the entry corresponding to the offset within the section
864 */
865 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
866
867 if (Entry == 0)
868 {
869 /*
870 * If the entry is zero (and it can't change because we have
871 * locked the segment) then we need to load the page.
872 */
873
874 /*
875 * Release all our locks and read in the page from disk
876 */
877 MmUnlockSectionSegment(Segment);
878 MmUnlockAddressSpace(AddressSpace);
879
880 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
881 (Offset > Segment->RawLength && Section->AllocationAttributes & SEC_IMAGE))
882 {
883 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
884 }
885 else
886 {
887 Status = MiReadPage(MemoryArea, Offset, &Page);
888 }
889 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
890 {
891 /*
892 * FIXME: What do we know in this case?
893 */
894 DPRINT1("MiReadPage or MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
895 /*
896 * Cleanup and release locks
897 */
898 MmLockAddressSpace(AddressSpace);
899 PageOp->Status = Status;
900 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
901 MmReleasePageOp(PageOp);
902 DPRINT("Address 0x%.8X\n", Address);
903 return(Status);
904 }
905 /*
906 * Relock the address space and segment
907 */
908 MmLockAddressSpace(AddressSpace);
909 MmLockSectionSegment(Segment);
910
911 /*
912 * Check the entry. No one should change the status of a page
913 * that has a pending page-in.
914 */
915 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
916 if (Entry != Entry1)
917 {
918 DbgPrint("Someone changed ppte entry while we slept\n");
919 KeBugCheck(0);
920 }
921
922 /*
923 * Mark the offset within the section as having valid, in-memory
924 * data
925 */
926 Entry = Page.u.LowPart;
927 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
928 MmSharePageEntrySectionSegment(Segment, Offset);
929 MmUnlockSectionSegment(Segment);
930
931 Status = MmCreateVirtualMapping(AddressSpace->Process,
932 Address,
933 Attributes,
934 Page,
935 FALSE);
936 if (Status == STATUS_NO_MEMORY)
937 {
938 MmUnlockAddressSpace(AddressSpace);
939 Status = MmCreateVirtualMapping(AddressSpace->Process,
940 Address,
941 Attributes,
942 Page,
943 TRUE);
944 MmLockAddressSpace(AddressSpace);
945 }
946 if (!NT_SUCCESS(Status))
947 {
948 DbgPrint("Unable to create virtual mapping\n");
949 KeBugCheck(0);
950 }
951 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
952
953 if (Locked)
954 {
955 MmLockPage(Page);
956 }
957 PageOp->Status = STATUS_SUCCESS;
958 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
959 MmReleasePageOp(PageOp);
960 DPRINT("Address 0x%.8X\n", Address);
961 return(STATUS_SUCCESS);
962 }
963 else if (IS_SWAP_FROM_SSE(Entry))
964 {
965 SWAPENTRY SwapEntry;
966 PMDL Mdl;
967
968 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
969
970 /*
971 * Release all our locks and read in the page from disk
972 */
973 MmUnlockSectionSegment(Segment);
974
975 MmUnlockAddressSpace(AddressSpace);
976
977 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
978 if (!NT_SUCCESS(Status))
979 {
980 KeBugCheck(0);
981 }
982
983 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
984 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
985 Status = MmReadFromSwapPage(SwapEntry, Mdl);
986 if (!NT_SUCCESS(Status))
987 {
988 KeBugCheck(0);
989 }
990
991 /*
992 * Relock the address space and segment
993 */
994 MmLockAddressSpace(AddressSpace);
995 MmLockSectionSegment(Segment);
996
997 /*
998 * Check the entry. No one should change the status of a page
999 * that has a pending page-in.
1000 */
1001 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1002 if (Entry != Entry1)
1003 {
1004 DbgPrint("Someone changed ppte entry while we slept\n");
1005 KeBugCheck(0);
1006 }
1007
1008 /*
1009 * Mark the offset within the section as having valid, in-memory
1010 * data
1011 */
1012 Entry = Page.u.LowPart;
1013 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1014 MmSharePageEntrySectionSegment(Segment, Offset);
1015 MmUnlockSectionSegment(Segment);
1016
1017 /*
1018 * Save the swap entry.
1019 */
1020 MmSetSavedSwapEntryPage(Page, SwapEntry);
1021 Status = MmCreateVirtualMapping(AddressSpace->Process,
1022 Address,
1023 Region->Protect,
1024 Page,
1025 FALSE);
1026 if (Status == STATUS_NO_MEMORY)
1027 {
1028 MmUnlockAddressSpace(AddressSpace);
1029 Status = MmCreateVirtualMapping(AddressSpace->Process,
1030 Address,
1031 Region->Protect,
1032 Page,
1033 TRUE);
1034 MmLockAddressSpace(AddressSpace);
1035 }
1036 if (!NT_SUCCESS(Status))
1037 {
1038 DbgPrint("Unable to create virtual mapping\n");
1039 KeBugCheck(0);
1040 }
1041 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1042 if (Locked)
1043 {
1044 MmLockPage(Page);
1045 }
1046 PageOp->Status = STATUS_SUCCESS;
1047 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1048 MmReleasePageOp(PageOp);
1049 DPRINT("Address 0x%.8X\n", Address);
1050 return(STATUS_SUCCESS);
1051 }
1052 else
1053 {
1054 /*
1055 * If the section offset is already in-memory and valid then just
1056 * take another reference to the page
1057 */
1058
1059 Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
1060 MmReferencePage(Page);
1061 MmSharePageEntrySectionSegment(Segment, Offset);
1062 MmUnlockSectionSegment(Segment);
1063
1064 Status = MmCreateVirtualMapping(AddressSpace->Process,
1065 Address,
1066 Attributes,
1067 Page,
1068 FALSE);
1069 if (Status == STATUS_NO_MEMORY)
1070 {
1071 MmUnlockAddressSpace(AddressSpace);
1072 Status = MmCreateVirtualMapping(AddressSpace->Process,
1073 Address,
1074 Attributes,
1075 Page,
1076 TRUE);
1077 MmLockAddressSpace(AddressSpace);
1078 }
1079 if (!NT_SUCCESS(Status))
1080 {
1081 DbgPrint("Unable to create virtual mapping\n");
1082 KeBugCheck(0);
1083 }
1084 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1085 if (Locked)
1086 {
1087 MmLockPage(Page);
1088 }
1089 PageOp->Status = STATUS_SUCCESS;
1090 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1091 MmReleasePageOp(PageOp);
1092 DPRINT("Address 0x%.8X\n", Address);
1093 return(STATUS_SUCCESS);
1094 }
1095 }
1096
1097 NTSTATUS
1098 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1099 MEMORY_AREA* MemoryArea,
1100 PVOID Address,
1101 BOOLEAN Locked)
1102 {
1103 PMM_SECTION_SEGMENT Segment;
1104 PSECTION_OBJECT Section;
1105 PHYSICAL_ADDRESS OldPage;
1106 PHYSICAL_ADDRESS NewPage;
1107 PVOID NewAddress;
1108 NTSTATUS Status;
1109 ULONG PAddress;
1110 ULONG Offset;
1111 PMM_PAGEOP PageOp;
1112 PMM_REGION Region;
1113 LARGE_INTEGER Timeout;
1114
1115 /*
1116 * Check if the page has been paged out or has already been set readwrite
1117 */
1118 if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1119 MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1120 {
1121 DPRINT("Address 0x%.8X\n", Address);
1122 return(STATUS_SUCCESS);
1123 }
1124
1125 /*
1126 * Find the offset of the page
1127 */
1128 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1129 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
1130
1131 Segment = MemoryArea->Data.SectionData.Segment;
1132 Section = MemoryArea->Data.SectionData.Section;
1133 Region = MmFindRegion(MemoryArea->BaseAddress,
1134 &MemoryArea->Data.SectionData.RegionListHead,
1135 Address, NULL);
1136 /*
1137 * Lock the segment
1138 */
1139 MmLockSectionSegment(Segment);
1140
1141 /*
1142 * Sanity check.
1143 */
1144 if (MmGetPageEntrySectionSegment(Segment, Offset) == 0)
1145 {
1146 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1147 Address);
1148 }
1149 MmUnlockSectionSegment(Segment);
1150 /*
1151 * Check if we are doing COW
1152 */
1153 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1154 (Region->Protect == PAGE_READWRITE ||
1155 Region->Protect == PAGE_EXECUTE_READWRITE)))
1156 {
1157 DPRINT("Address 0x%.8X\n", Address);
1158 return(STATUS_UNSUCCESSFUL);
1159 }
1160
1161 /*
1162 * Get or create a pageop
1163 */
1164 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
1165 MM_PAGEOP_ACCESSFAULT);
1166 if (PageOp == NULL)
1167 {
1168 DPRINT1("MmGetPageOp failed\n");
1169 KeBugCheck(0);
1170 }
1171
1172 /*
1173 * Wait for any other operations to complete
1174 */
1175 if (PageOp->Thread != PsGetCurrentThread())
1176 {
1177 MmUnlockAddressSpace(AddressSpace);
1178 Timeout.QuadPart = -100000000LL; // 10 sec
1179 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1180 0,
1181 KernelMode,
1182 FALSE,
1183 &Timeout);
1184 /*
1185 * Check for various strange conditions
1186 */
1187 if (Status == STATUS_TIMEOUT)
1188 {
1189 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1190 KeBugCheck(0);
1191 }
1192 if (PageOp->Status == STATUS_PENDING)
1193 {
1194 DPRINT1("Woke for page op before completion\n");
1195 KeBugCheck(0);
1196 }
1197 /*
1198 * Restart the operation
1199 */
1200 MmLockAddressSpace(AddressSpace);
1201 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1202 MmReleasePageOp(PageOp);
1203 DPRINT("Address 0x%.8X\n", Address);
1204 return(STATUS_MM_RESTART_OPERATION);
1205 }
1206
1207 /*
1208 * Release locks now we have the pageop
1209 */
1210 MmUnlockAddressSpace(AddressSpace);
1211
1212 /*
1213 * Allocate a page
1214 */
1215 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1216 if (!NT_SUCCESS(Status))
1217 {
1218 KeBugCheck(0);
1219 }
1220
1221 /*
1222 * Copy the old page
1223 */
1224 OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1225
1226 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1227 memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
1228 ExUnmapPage(NewAddress);
1229
1230 /*
1231 * Delete the old entry.
1232 */
1233 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1234
1235 /*
1236 * Set the PTE to point to the new page
1237 */
1238 MmLockAddressSpace(AddressSpace);
1239 Status = MmCreateVirtualMapping(AddressSpace->Process,
1240 Address,
1241 Region->Protect,
1242 NewPage,
1243 FALSE);
1244 if (Status == STATUS_NO_MEMORY)
1245 {
1246 MmUnlockAddressSpace(AddressSpace);
1247 Status = MmCreateVirtualMapping(AddressSpace->Process,
1248 Address,
1249 Region->Protect,
1250 NewPage,
1251 TRUE);
1252 MmLockAddressSpace(AddressSpace);
1253 }
1254 if (!NT_SUCCESS(Status))
1255 {
1256 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1257 KeBugCheck(0);
1258 return(Status);
1259 }
1260 MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
1261 if (!NT_SUCCESS(Status))
1262 {
1263 DbgPrint("Unable to create virtual mapping\n");
1264 KeBugCheck(0);
1265 }
1266 if (Locked)
1267 {
1268 MmLockPage(NewPage);
1269 }
1270
1271 /*
1272 * Unshare the old page.
1273 */
1274 MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
1275 MmLockSectionSegment(Segment);
1276 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE);
1277 MmUnlockSectionSegment(Segment);
1278 MmReleasePageMemoryConsumer(MC_USER, OldPage);
1279
1280 PageOp->Status = STATUS_SUCCESS;
1281 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1282 MmReleasePageOp(PageOp);
1283 DPRINT("Address 0x%.8X\n", Address);
1284 return(STATUS_SUCCESS);
1285 }
1286
1287 VOID
1288 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1289 {
1290 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1291 BOOL WasDirty;
1292 PHYSICAL_ADDRESS Page;
1293
1294 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1295 MmDeleteVirtualMapping(Process,
1296 Address,
1297 FALSE,
1298 &WasDirty,
1299 &Page);
1300 if (WasDirty)
1301 {
1302 PageOutContext->WasDirty = TRUE;
1303 }
1304 if (!PageOutContext->Private)
1305 {
1306 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1307 PageOutContext->Segment,
1308 PageOutContext->Offset,
1309 PageOutContext->WasDirty);
1310 }
1311 MmReleasePageMemoryConsumer(MC_USER, Page);
1312 DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
1313 }
1314
1315 NTSTATUS
1316 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1317 MEMORY_AREA* MemoryArea,
1318 PVOID Address,
1319 PMM_PAGEOP PageOp)
1320 {
1321 PHYSICAL_ADDRESS PhysicalAddress;
1322 MM_SECTION_PAGEOUT_CONTEXT Context;
1323 SWAPENTRY SwapEntry;
1324 PMDL Mdl;
1325 ULONG Entry;
1326 ULONG FileOffset;
1327 NTSTATUS Status;
1328 PFILE_OBJECT FileObject;
1329 PBCB Bcb = NULL;
1330 BOOLEAN DirectMapped;
1331 BOOLEAN IsImageSection;
1332
1333 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1334
1335 /*
1336 * Get the segment and section.
1337 */
1338 Context.Segment = MemoryArea->Data.SectionData.Segment;
1339 Context.Section = MemoryArea->Data.SectionData.Section;
1340
1341 Context.Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1342 FileOffset = Context.Offset + Context.Segment->FileOffset;
1343
1344 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1345
1346 FileObject = Context.Section->FileObject;
1347 DirectMapped = FALSE;
1348 if (FileObject != NULL)
1349 {
1350 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1351
1352 /*
1353 * If the file system is letting us go directly to the cache and the
1354 * memory area was mapped at an offset in the file which is page aligned
1355 * then note this is a direct mapped page.
1356 */
1357 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1358 (FileOffset % PAGE_SIZE) == 0 &&
1359 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1360 {
1361 DirectMapped = TRUE;
1362 }
1363 }
1364
1365
1366 /*
1367 * This should never happen since mappings of physical memory are never
1368 * placed in the rmap lists.
1369 */
1370 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1371 {
1372 DPRINT1("Trying to page out from physical memory section address 0x%X "
1373 "process %d\n", Address,
1374 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1375 KeBugCheck(0);
1376 }
1377
1378 /*
1379 * Get the section segment entry and the physical address.
1380 */
1381 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1382 if (!MmIsPagePresent(AddressSpace->Process, Address))
1383 {
1384 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1385 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1386 KeBugCheck(0);
1387 }
1388 PhysicalAddress =
1389 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1390 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1391
1392 /*
1393 * Prepare the context structure for the rmap delete call.
1394 */
1395 Context.WasDirty = FALSE;
1396 if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1397 IS_SWAP_FROM_SSE(Entry) ||
1398 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1399 {
1400 Context.Private = TRUE;
1401 }
1402 else
1403 {
1404 Context.Private = FALSE;
1405 }
1406
1407 /*
1408 * Paging out data mapped read-only is easy.
1409 */
1410 if (Context.Segment->Protection & (PAGE_READONLY|PAGE_EXECUTE_READ))
1411 {
1412 /*
1413 * Read-only data should never be in the swapfile.
1414 */
1415 if (SwapEntry != 0)
1416 {
1417 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1418 "paddress 0x%.8X\n", SwapEntry, Address,
1419 PhysicalAddress);
1420 KeBugCheck(0);
1421 }
1422
1423 /*
1424 * Read-only data should never be COWed
1425 */
1426 if (Context.Private)
1427 {
1428 DPRINT1("Had private copy of read-only page.\n");
1429 KeBugCheck(0);
1430 }
1431
1432 /*
1433 * Delete all mappings of this page.
1434 */
1435 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context,
1436 MmPageOutDeleteMapping);
1437 if (Context.WasDirty)
1438 {
1439 DPRINT1("Had a dirty page of a read-only page.\n");
1440 KeBugCheck(0);
1441 }
1442
1443 PageOp->Status = STATUS_SUCCESS;
1444 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1445 MmReleasePageOp(PageOp);
1446 return(STATUS_SUCCESS);
1447 }
1448
1449 /*
1450 * Otherwise we have read-write data.
1451 */
1452
1453 /*
1454 * Take an additional reference to the page or the cache segment.
1455 */
1456 if (DirectMapped && !Context.Private)
1457 {
1458 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1459 {
1460 DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1461 KeBugCheck(0);
1462 }
1463 }
1464 else
1465 {
1466 MmReferencePage(PhysicalAddress);
1467 }
1468
1469 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1470
1471 /*
1472 * If this wasn't a private page then we should have reduced the entry to
1473 * zero by deleting all the rmaps.
1474 */
1475 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1476 {
1477 KeBugCheck(0);
1478 }
1479
1480 /*
1481 * If the page wasn't dirty then we can just free it as for a readonly page.
1482 * Since we unmapped all the mappings above we know it will not suddenly
1483 * become dirty.
1484 */
1485 if (!Context.WasDirty)
1486 {
1487 if (Context.Private)
1488 {
1489 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1490 if (!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1491 SwapEntry == 0)
1492 {
1493 DPRINT1("Private page, non-dirty but not swapped out "
1494 "process %d address 0x%.8X\n",
1495 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0,
1496 Address);
1497 KeBugCheck(0);
1498 }
1499 else
1500 {
1501 Status = MmCreatePageFileMapping(AddressSpace->Process,
1502 Address,
1503 SwapEntry);
1504 if (!NT_SUCCESS(Status))
1505 {
1506 KeBugCheck(0);
1507 }
1508 }
1509 }
1510 if (DirectMapped && !Context.Private)
1511 {
1512 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1513 if (!NT_SUCCESS(Status))
1514 {
1515 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1516 KeBugCheck(0);
1517 }
1518 }
1519 else
1520 {
1521 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1522 }
1523
1524 PageOp->Status = STATUS_SUCCESS;
1525 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1526 MmReleasePageOp(PageOp);
1527 return(STATUS_SUCCESS);
1528 }
1529
1530 /*
1531 * If this page was direct mapped from the cache then the cache manager
1532 * will already have taken care of writing it back.
1533 */
1534 if (DirectMapped && !Context.Private)
1535 {
1536 assert(SwapEntry == 0);
1537 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1538 if (!NT_SUCCESS(Status))
1539 {
1540 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
1541 KeBugCheck(0);
1542 }
1543 PageOp->Status = STATUS_SUCCESS;
1544 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1545 MmReleasePageOp(PageOp);
1546 return(STATUS_SUCCESS);
1547 }
1548
1549 /*
1550 * If necessary, allocate an entry in the paging file for this page
1551 */
1552 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1553 if (SwapEntry == 0)
1554 {
1555 SwapEntry = MmAllocSwapPage();
1556 if (SwapEntry == 0)
1557 {
1558 MmShowOutOfSpaceMessagePagingFile();
1559
1560 /*
1561 * For private pages restore the old mappings.
1562 */
1563 if (Context.Private)
1564 {
1565 Status = MmCreateVirtualMapping(MemoryArea->Process,
1566 Address,
1567 MemoryArea->Attributes,
1568 PhysicalAddress,
1569 FALSE);
1570 MmSetDirtyPage(MemoryArea->Process, Address);
1571 MmInsertRmap(PhysicalAddress,
1572 MemoryArea->Process,
1573 Address);
1574 }
1575 else
1576 {
1577 /*
1578 * For non-private pages if the page wasn't direct mapped then
1579 * set it back into the section segment entry so we don't loose
1580 * our copy. Otherwise it will be handled by the cache manager.
1581 */
1582 Status = MmCreateVirtualMapping(MemoryArea->Process,
1583 Address,
1584 MemoryArea->Attributes,
1585 PhysicalAddress,
1586 FALSE);
1587 MmSetDirtyPage(MemoryArea->Process, Address);
1588 MmInsertRmap(PhysicalAddress,
1589 MemoryArea->Process,
1590 Address);
1591 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset,
1592 PhysicalAddress.u.LowPart);
1593 MmSharePageEntrySectionSegment(Context.Segment, Context.Offset);
1594 }
1595 PageOp->Status = STATUS_UNSUCCESSFUL;
1596 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1597 MmReleasePageOp(PageOp);
1598 return(STATUS_UNSUCCESSFUL);
1599 }
1600 }
1601
1602 /*
1603 * Write the page to the pagefile
1604 */
1605 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1606 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1607 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1608 if (!NT_SUCCESS(Status))
1609 {
1610 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1611 Status);
1612 /*
1613 * As above: undo our actions.
1614 * FIXME: Also free the swap page.
1615 */
1616 if (Context.Private)
1617 {
1618 Status = MmCreateVirtualMapping(MemoryArea->Process,
1619 Address,
1620 MemoryArea->Attributes,
1621 PhysicalAddress,
1622 FALSE);
1623 MmSetDirtyPage(MemoryArea->Process, Address);
1624 MmInsertRmap(PhysicalAddress,
1625 MemoryArea->Process,
1626 Address);
1627 }
1628 else
1629 {
1630 Status = MmCreateVirtualMapping(MemoryArea->Process,
1631 Address,
1632 MemoryArea->Attributes,
1633 PhysicalAddress,
1634 FALSE);
1635 MmSetDirtyPage(MemoryArea->Process, Address);
1636 MmInsertRmap(PhysicalAddress,
1637 MemoryArea->Process,
1638 Address);
1639 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset,
1640 PhysicalAddress.u.LowPart);
1641 MmSharePageEntrySectionSegment(Context.Segment, Context.Offset);
1642 }
1643 PageOp->Status = STATUS_UNSUCCESSFUL;
1644 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1645 MmReleasePageOp(PageOp);
1646 return(STATUS_UNSUCCESSFUL);
1647 }
1648
1649 /*
1650 * Otherwise we have succeeded.
1651 */
1652 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1653 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1654 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1655
1656 if (Context.Private)
1657 {
1658 Status = MmCreatePageFileMapping(MemoryArea->Process,
1659 Address,
1660 SwapEntry);
1661 if (!NT_SUCCESS(Status))
1662 {
1663 KeBugCheck(0);
1664 }
1665 }
1666 else
1667 {
1668 Entry = MAKE_SWAP_SSE(SwapEntry);
1669 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1670 }
1671
1672 PageOp->Status = STATUS_SUCCESS;
1673 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1674 MmReleasePageOp(PageOp);
1675 return(STATUS_SUCCESS);
1676 }
1677
1678 NTSTATUS
1679 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1680 PMEMORY_AREA MemoryArea,
1681 PVOID Address,
1682 PMM_PAGEOP PageOp)
1683 {
1684 ULONG Offset;
1685 PSECTION_OBJECT Section;
1686 PMM_SECTION_SEGMENT Segment;
1687 PHYSICAL_ADDRESS PhysicalAddress;
1688 SWAPENTRY SwapEntry;
1689 PMDL Mdl;
1690 ULONG Entry;
1691 BOOLEAN Private;
1692 NTSTATUS Status;
1693 PFILE_OBJECT FileObject;
1694 PBCB Bcb = NULL;
1695 BOOLEAN DirectMapped;
1696 BOOLEAN IsImageSection;
1697
1698 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1699
1700 Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1701
1702 /*
1703 * Get the segment and section.
1704 */
1705 Segment = MemoryArea->Data.SectionData.Segment;
1706 Section = MemoryArea->Data.SectionData.Section;
1707 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1708
1709 FileObject = Section->FileObject;
1710 DirectMapped = FALSE;
1711 if (FileObject != NULL)
1712 {
1713 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1714
1715 /*
1716 * If the file system is letting us go directly to the cache and the
1717 * memory area was mapped at an offset in the file which is page aligned
1718 * then note this is a direct mapped page.
1719 */
1720 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1721 (Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
1722 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1723 {
1724 DirectMapped = TRUE;
1725 }
1726 }
1727
1728 /*
1729 * This should never happen since mappings of physical memory are never
1730 * placed in the rmap lists.
1731 */
1732 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1733 {
1734 DPRINT1("Trying to write back page from physical memory mapped at %X "
1735 "process %d\n", Address,
1736 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1737 KeBugCheck(0);
1738 }
1739
1740 /*
1741 * Get the section segment entry and the physical address.
1742 */
1743 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1744 if (!MmIsPagePresent(AddressSpace->Process, Address))
1745 {
1746 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1747 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1748 KeBugCheck(0);
1749 }
1750 PhysicalAddress =
1751 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1752 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1753
1754 /*
1755 * Check for a private (COWed) page.
1756 */
1757 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1758 IS_SWAP_FROM_SSE(Entry) ||
1759 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1760 {
1761 Private = TRUE;
1762 }
1763 else
1764 {
1765 Private = FALSE;
1766 }
1767
1768 /*
1769 * Speculatively set all mappings of the page to clean.
1770 */
1771 MmSetCleanAllRmaps(PhysicalAddress);
1772
1773 /*
1774 * If this page was direct mapped from the cache then the cache manager
1775 * will take care of writing it back to disk.
1776 */
1777 if (DirectMapped && !Private)
1778 {
1779 assert(SwapEntry == 0);
1780 CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
1781 PageOp->Status = STATUS_SUCCESS;
1782 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1783 MmReleasePageOp(PageOp);
1784 return(STATUS_SUCCESS);
1785 }
1786
1787 /*
1788 * If necessary, allocate an entry in the paging file for this page
1789 */
1790 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1791 if (SwapEntry == 0)
1792 {
1793 SwapEntry = MmAllocSwapPage();
1794 if (SwapEntry == 0)
1795 {
1796 MmSetDirtyAllRmaps(PhysicalAddress);
1797 PageOp->Status = STATUS_UNSUCCESSFUL;
1798 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1799 MmReleasePageOp(PageOp);
1800 return(STATUS_UNSUCCESSFUL);
1801 }
1802 }
1803
1804 /*
1805 * Write the page to the pagefile
1806 */
1807 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1808 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1809 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1810 if (!NT_SUCCESS(Status))
1811 {
1812 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1813 Status);
1814 MmSetDirtyAllRmaps(PhysicalAddress);
1815 PageOp->Status = STATUS_UNSUCCESSFUL;
1816 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1817 MmReleasePageOp(PageOp);
1818 return(STATUS_UNSUCCESSFUL);
1819 }
1820
1821 /*
1822 * Otherwise we have succeeded.
1823 */
1824 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1825 MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
1826 PageOp->Status = STATUS_SUCCESS;
1827 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1828 MmReleasePageOp(PageOp);
1829 return(STATUS_SUCCESS);
1830 }
1831
1832 VOID STATIC
1833 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1834 PVOID BaseAddress,
1835 ULONG RegionSize,
1836 ULONG OldType,
1837 ULONG OldProtect,
1838 ULONG NewType,
1839 ULONG NewProtect)
1840 {
1841 PMEMORY_AREA MemoryArea;
1842 PMM_SECTION_SEGMENT Segment;
1843 BOOL DoCOW = FALSE;
1844 ULONG i;
1845
1846 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1847 Segment = MemoryArea->Data.SectionData.Segment;
1848
1849 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1850 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1851 {
1852 DoCOW = TRUE;
1853 }
1854
1855 if (OldProtect != NewProtect)
1856 {
1857 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1858 {
1859 PVOID Address = BaseAddress + (i * PAGE_SIZE);
1860 ULONG Protect = NewProtect;
1861
1862 /*
1863 * If we doing COW for this segment then check if the page is
1864 * already private.
1865 */
1866 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1867 {
1868 ULONG Offset;
1869 ULONG Entry;
1870 LARGE_INTEGER PhysicalAddress;
1871
1872 Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
1873 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1874 PhysicalAddress =
1875 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1876
1877 Protect = PAGE_READONLY;
1878 if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1879 IS_SWAP_FROM_SSE(Entry) ||
1880 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
1881 {
1882 Protect = NewProtect;
1883 }
1884 }
1885
1886 if (MmIsPagePresent(AddressSpace->Process, Address))
1887 {
1888 MmSetPageProtect(AddressSpace->Process, BaseAddress,
1889 Protect);
1890 }
1891 }
1892 }
1893 }
1894
1895 NTSTATUS
1896 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1897 PMEMORY_AREA MemoryArea,
1898 PVOID BaseAddress,
1899 ULONG Length,
1900 ULONG Protect,
1901 PULONG OldProtect)
1902 {
1903 PMM_REGION Region;
1904 NTSTATUS Status;
1905
1906 Length =
1907 min(Length, (ULONG) (MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress));
1908 Region = MmFindRegion(MemoryArea->BaseAddress,
1909 &MemoryArea->Data.SectionData.RegionListHead,
1910 BaseAddress, NULL);
1911 *OldProtect = Region->Protect;
1912 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1913 &MemoryArea->Data.SectionData.RegionListHead,
1914 BaseAddress, Length, Region->Type, Protect,
1915 MmAlterViewAttributes);
1916
1917 return(Status);
1918 }
1919
1920 NTSTATUS STDCALL
1921 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1922 PVOID Address,
1923 PMEMORY_BASIC_INFORMATION Info,
1924 PULONG ResultLength)
1925 {
1926 PMM_REGION Region;
1927 PVOID RegionBaseAddress;
1928
1929 Region = MmFindRegion(MemoryArea->BaseAddress,
1930 &MemoryArea->Data.SectionData.RegionListHead,
1931 Address, &RegionBaseAddress);
1932 if (Region == NULL)
1933 {
1934 return STATUS_UNSUCCESSFUL;
1935 }
1936 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
1937 Info->AllocationBase = MemoryArea->BaseAddress;
1938 Info->AllocationProtect = MemoryArea->Attributes;
1939 Info->RegionSize = MemoryArea->Length;
1940 Info->State = MEM_COMMIT;
1941 Info->Protect = Region->Protect;
1942 if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
1943 {
1944 Info->Type = MEM_IMAGE;
1945 }
1946 else
1947 {
1948 Info->Type = MEM_MAPPED;
1949 }
1950
1951 return(STATUS_SUCCESS);
1952 }
1953
1954 VOID STDCALL
1955 MmpDeleteSection(PVOID ObjectBody)
1956 {
1957 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
1958
1959 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
1960 if (Section->AllocationAttributes & SEC_IMAGE)
1961 {
1962 ULONG i;
1963 ULONG NrSegments;
1964 PMM_SECTION_SEGMENT SectionSegments;
1965
1966 SectionSegments = Section->ImageSection->Segments;
1967 NrSegments = Section->ImageSection->NrSegments;
1968
1969 for (i = 0; i < NrSegments; i++)
1970 {
1971 InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
1972 }
1973 }
1974 else
1975 {
1976 InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
1977 }
1978 if (Section->FileObject != NULL)
1979 {
1980 CcRosDereferenceCache(Section->FileObject);
1981 ObDereferenceObject(Section->FileObject);
1982 Section->FileObject = NULL;
1983 }
1984
1985 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
1986 {
1987 MmFreePageTablesSectionSegment(Section->Segment);
1988 ExFreePool(Section->Segment);
1989 }
1990 }
1991
1992 VOID STDCALL
1993 MmpCloseSection(PVOID ObjectBody,
1994 ULONG HandleCount)
1995 {
1996 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1997 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
1998 }
1999
2000 NTSTATUS STDCALL
2001 MmpCreateSection(PVOID ObjectBody,
2002 PVOID Parent,
2003 PWSTR RemainingPath,
2004 POBJECT_ATTRIBUTES ObjectAttributes)
2005 {
2006 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2007 ObjectBody, Parent, RemainingPath);
2008
2009 if (RemainingPath == NULL)
2010 {
2011 return(STATUS_SUCCESS);
2012 }
2013
2014 if (wcschr(RemainingPath+1, L'\\') != NULL)
2015 {
2016 return(STATUS_UNSUCCESSFUL);
2017 }
2018 return(STATUS_SUCCESS);
2019 }
2020
2021 NTSTATUS
2022 MmCreatePhysicalMemorySection(VOID)
2023 {
2024 HANDLE PhysSectionH;
2025 PSECTION_OBJECT PhysSection;
2026 NTSTATUS Status;
2027 OBJECT_ATTRIBUTES Obj;
2028 UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
2029 LARGE_INTEGER SectionSize;
2030
2031 /*
2032 * Create the section mapping physical memory
2033 */
2034 SectionSize.QuadPart = 0xFFFFFFFF;
2035 InitializeObjectAttributes(&Obj,
2036 &Name,
2037 0,
2038 NULL,
2039 NULL);
2040 Status = NtCreateSection(&PhysSectionH,
2041 SECTION_ALL_ACCESS,
2042 &Obj,
2043 &SectionSize,
2044 PAGE_EXECUTE_READWRITE,
2045 0,
2046 NULL);
2047 if (!NT_SUCCESS(Status))
2048 {
2049 DbgPrint("Failed to create PhysicalMemory section\n");
2050 KeBugCheck(0);
2051 }
2052 Status = ObReferenceObjectByHandle(PhysSectionH,
2053 SECTION_ALL_ACCESS,
2054 NULL,
2055 KernelMode,
2056 (PVOID*)&PhysSection,
2057 NULL);
2058 if (!NT_SUCCESS(Status))
2059 {
2060 DbgPrint("Failed to reference PhysicalMemory section\n");
2061 KeBugCheck(0);
2062 }
2063 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2064 ObDereferenceObject((PVOID)PhysSection);
2065
2066 return(STATUS_SUCCESS);
2067 }
2068
2069 NTSTATUS
2070 MmInitSectionImplementation(VOID)
2071 {
2072 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
2073
2074 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
2075
2076 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
2077 MmSectionObjectType->TotalObjects = 0;
2078 MmSectionObjectType->TotalHandles = 0;
2079 MmSectionObjectType->MaxObjects = ULONG_MAX;
2080 MmSectionObjectType->MaxHandles = ULONG_MAX;
2081 MmSectionObjectType->PagedPoolCharge = 0;
2082 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
2083 MmSectionObjectType->Mapping = &MmpSectionMapping;
2084 MmSectionObjectType->Dump = NULL;
2085 MmSectionObjectType->Open = NULL;
2086 MmSectionObjectType->Close = MmpCloseSection;
2087 MmSectionObjectType->Delete = MmpDeleteSection;
2088 MmSectionObjectType->Parse = NULL;
2089 MmSectionObjectType->Security = NULL;
2090 MmSectionObjectType->QueryName = NULL;
2091 MmSectionObjectType->OkayToClose = NULL;
2092 MmSectionObjectType->Create = MmpCreateSection;
2093 MmSectionObjectType->DuplicationNotify = NULL;
2094
2095 return(STATUS_SUCCESS);
2096 }
2097
2098 NTSTATUS
2099 MmCreatePageFileSection(PHANDLE SectionHandle,
2100 ACCESS_MASK DesiredAccess,
2101 POBJECT_ATTRIBUTES ObjectAttributes,
2102 PLARGE_INTEGER UMaximumSize,
2103 ULONG SectionPageProtection,
2104 ULONG AllocationAttributes)
2105 /*
2106 * Create a section which is backed by the pagefile
2107 */
2108 {
2109 LARGE_INTEGER MaximumSize;
2110 PSECTION_OBJECT Section;
2111 PMM_SECTION_SEGMENT Segment;
2112 NTSTATUS Status;
2113
2114 if (UMaximumSize == NULL)
2115 {
2116 return(STATUS_UNSUCCESSFUL);
2117 }
2118 MaximumSize = *UMaximumSize;
2119
2120 /*
2121 * Check the protection
2122 */
2123 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2124 SectionPageProtection)
2125 {
2126 return(STATUS_INVALID_PAGE_PROTECTION);
2127 }
2128
2129 /*
2130 * Create the section
2131 */
2132 Status = ObRosCreateObject(SectionHandle,
2133 DesiredAccess,
2134 ObjectAttributes,
2135 MmSectionObjectType,
2136 (PVOID*)&Section);
2137 if (!NT_SUCCESS(Status))
2138 {
2139 return(Status);
2140 }
2141
2142 /*
2143 * Initialize it
2144 */
2145 Section->SectionPageProtection = SectionPageProtection;
2146 Section->AllocationAttributes = AllocationAttributes;
2147 InitializeListHead(&Section->ViewListHead);
2148 KeInitializeSpinLock(&Section->ViewListLock);
2149 Section->FileObject = NULL;
2150 Section->MaximumSize = MaximumSize;
2151 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2152 TAG_MM_SECTION_SEGMENT);
2153 if (Segment == NULL)
2154 {
2155 ZwClose(*SectionHandle);
2156 ObDereferenceObject(Section);
2157 return(STATUS_NO_MEMORY);
2158 }
2159 Section->Segment = Segment;
2160 Segment->ReferenceCount = 1;
2161 ExInitializeFastMutex(&Segment->Lock);
2162 Segment->FileOffset = 0;
2163 Segment->Protection = SectionPageProtection;
2164 Segment->Attributes = AllocationAttributes;
2165 Segment->Length = MaximumSize.u.LowPart;
2166 Segment->Flags = MM_PAGEFILE_SEGMENT;
2167 Segment->WriteCopy = FALSE;
2168 ObDereferenceObject(Section);
2169 return(STATUS_SUCCESS);
2170 }
2171
2172
2173 NTSTATUS
2174 MmCreateDataFileSection(PHANDLE SectionHandle,
2175 ACCESS_MASK DesiredAccess,
2176 POBJECT_ATTRIBUTES ObjectAttributes,
2177 PLARGE_INTEGER UMaximumSize,
2178 ULONG SectionPageProtection,
2179 ULONG AllocationAttributes,
2180 HANDLE FileHandle)
2181 /*
2182 * Create a section backed by a data file
2183 */
2184 {
2185 PSECTION_OBJECT Section;
2186 NTSTATUS Status;
2187 LARGE_INTEGER MaximumSize;
2188 PFILE_OBJECT FileObject;
2189 PMM_SECTION_SEGMENT Segment;
2190 ULONG FileAccess;
2191 IO_STATUS_BLOCK Iosb;
2192 LARGE_INTEGER Offset;
2193 CHAR Buffer;
2194
2195 /*
2196 * Check the protection
2197 */
2198 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2199 SectionPageProtection)
2200 {
2201 return(STATUS_INVALID_PAGE_PROTECTION);
2202 }
2203
2204 /*
2205 * Read a bit so caching is initiated for the file object.
2206 * This is only needed because MiReadPage currently cannot
2207 * handle non-cached streams.
2208 */
2209 Offset.QuadPart = 0;
2210 Status = ZwReadFile(FileHandle,
2211 NULL,
2212 NULL,
2213 NULL,
2214 &Iosb,
2215 &Buffer,
2216 sizeof (Buffer),
2217 &Offset,
2218 0);
2219 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2220 {
2221 return(Status);
2222 }
2223
2224 /*
2225 * Create the section
2226 */
2227 Status = ObRosCreateObject(SectionHandle,
2228 DesiredAccess,
2229 ObjectAttributes,
2230 MmSectionObjectType,
2231 (PVOID*)&Section);
2232 if (!NT_SUCCESS(Status))
2233 {
2234 return(Status);
2235 }
2236
2237 /*
2238 * Initialize it
2239 */
2240 Section->SectionPageProtection = SectionPageProtection;
2241 Section->AllocationAttributes = AllocationAttributes;
2242 InitializeListHead(&Section->ViewListHead);
2243 KeInitializeSpinLock(&Section->ViewListLock);
2244
2245 /*
2246 * Check file access required
2247 */
2248 if (SectionPageProtection & PAGE_READWRITE ||
2249 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2250 {
2251 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2252 }
2253 else
2254 {
2255 FileAccess = FILE_READ_DATA;
2256 }
2257
2258 /*
2259 * Reference the file handle
2260 */
2261 Status = ObReferenceObjectByHandle(FileHandle,
2262 FileAccess,
2263 IoFileObjectType,
2264 UserMode,
2265 (PVOID*)&FileObject,
2266 NULL);
2267 if (!NT_SUCCESS(Status))
2268 {
2269 ZwClose(*SectionHandle);
2270 ObDereferenceObject(Section);
2271 return(Status);
2272 }
2273
2274 /*
2275 * We can't do memory mappings if the file system doesn't support the
2276 * standard FCB
2277 */
2278 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2279 {
2280 ZwClose(*SectionHandle);
2281 ObDereferenceObject(Section);
2282 ObDereferenceObject(FileObject);
2283 return(STATUS_INVALID_FILE_FOR_SECTION);
2284 }
2285
2286 /*
2287 * FIXME: Revise this once a locking order for file size changes is
2288 * decided
2289 */
2290 if (UMaximumSize != NULL)
2291 {
2292 MaximumSize = *UMaximumSize;
2293 }
2294 else
2295 {
2296 MaximumSize =
2297 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2298 }
2299
2300 if (MaximumSize.QuadPart >
2301 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2302 {
2303 IO_STATUS_BLOCK Iosb;
2304 Status = NtSetInformationFile(FileHandle,
2305 &Iosb,
2306 &MaximumSize,
2307 sizeof(LARGE_INTEGER),
2308 FileAllocationInformation);
2309 if (!NT_SUCCESS(Status))
2310 {
2311 ZwClose(*SectionHandle);
2312 ObDereferenceObject(Section);
2313 ObDereferenceObject(FileObject);
2314 return(STATUS_SECTION_NOT_EXTENDED);
2315 }
2316 }
2317
2318 /*
2319 * Lock the file
2320 */
2321 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2322 0,
2323 KernelMode,
2324 FALSE,
2325 NULL);
2326 if (Status != STATUS_SUCCESS)
2327 {
2328 ZwClose(*SectionHandle);
2329 ObDereferenceObject(Section);
2330 ObDereferenceObject(FileObject);
2331 return(Status);
2332 }
2333
2334 /*
2335 * If this file hasn't been mapped as a data file before then allocate a
2336 * section segment to describe the data file mapping
2337 */
2338 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2339 {
2340 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2341 TAG_MM_SECTION_SEGMENT);
2342 if (Segment == NULL)
2343 {
2344 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2345 ZwClose(*SectionHandle);
2346 ObDereferenceObject(Section);
2347 ObDereferenceObject(FileObject);
2348 return(STATUS_NO_MEMORY);
2349 }
2350 Section->Segment = Segment;
2351 Segment->ReferenceCount = 1;
2352 ExInitializeFastMutex(&Segment->Lock);
2353 /*
2354 * Set the lock before assigning the segment to the file object
2355 */
2356 ExAcquireFastMutex(&Segment->Lock);
2357 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2358
2359 Segment->FileOffset = 0;
2360 Segment->Protection = 0;
2361 Segment->Attributes = 0;
2362 Segment->Flags = MM_DATAFILE_SEGMENT;
2363 Segment->Characteristics = 0;
2364 Segment->WriteCopy = FALSE;
2365 if (AllocationAttributes & SEC_RESERVE)
2366 {
2367 Segment->Length = Segment->RawLength = 0;
2368 }
2369 else
2370 {
2371 Segment->RawLength = MaximumSize.u.LowPart;
2372 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2373 }
2374 Segment->VirtualAddress = NULL;
2375 }
2376 else
2377 {
2378 /*
2379 * If the file is already mapped as a data file then we may need
2380 * to extend it
2381 */
2382 Segment =
2383 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2384 DataSectionObject;
2385 Section->Segment = Segment;
2386 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2387 MmLockSectionSegment(Segment);
2388
2389 if (MaximumSize.u.LowPart > Segment->RawLength &&
2390 !(AllocationAttributes & SEC_RESERVE))
2391 {
2392 Segment->RawLength = MaximumSize.u.LowPart;
2393 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2394 }
2395 }
2396 MmUnlockSectionSegment(Segment);
2397 Section->FileObject = FileObject;
2398 Section->MaximumSize = MaximumSize;
2399 CcRosReferenceCache(FileObject);
2400 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2401 ObDereferenceObject(Section);
2402 return(STATUS_SUCCESS);
2403 }
2404
2405 static ULONG SectionCharacteristicsToProtect[16] =
2406 {
2407 PAGE_NOACCESS, // 0 = NONE
2408 PAGE_NOACCESS, // 1 = SHARED
2409 PAGE_EXECUTE, // 2 = EXECUTABLE
2410 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2411 PAGE_READONLY, // 4 = READABLE
2412 PAGE_READONLY, // 5 = READABLE, SHARED
2413 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2414 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2415 PAGE_READWRITE, // 8 = WRITABLE
2416 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2417 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2418 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2419 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2420 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2421 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2422 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2423 };
2424
2425 NTSTATUS
2426 MmCreateImageSection(PHANDLE SectionHandle,
2427 ACCESS_MASK DesiredAccess,
2428 POBJECT_ATTRIBUTES ObjectAttributes,
2429 PLARGE_INTEGER UMaximumSize,
2430 ULONG SectionPageProtection,
2431 ULONG AllocationAttributes,
2432 HANDLE FileHandle)
2433 {
2434 PSECTION_OBJECT Section;
2435 NTSTATUS Status;
2436 PFILE_OBJECT FileObject;
2437 IMAGE_DOS_HEADER DosHeader;
2438 IO_STATUS_BLOCK Iosb;
2439 LARGE_INTEGER Offset;
2440 IMAGE_NT_HEADERS PEHeader;
2441 PIMAGE_SECTION_HEADER ImageSections;
2442 PMM_SECTION_SEGMENT SectionSegments;
2443 ULONG NrSegments;
2444 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2445 ULONG i;
2446 ULONG Size;
2447 ULONG Characteristics;
2448 ULONG FileAccess = 0;
2449 /*
2450 * Check the protection
2451 */
2452 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2453 SectionPageProtection)
2454 {
2455 return(STATUS_INVALID_PAGE_PROTECTION);
2456 }
2457
2458 /*
2459 * Specifying a maximum size is meaningless for an image section
2460 */
2461 if (UMaximumSize != NULL)
2462 {
2463 return(STATUS_INVALID_PARAMETER_4);
2464 }
2465
2466 /*
2467 * Reference the file handle
2468 */
2469 Status = ObReferenceObjectByHandle(FileHandle,
2470 FileAccess,
2471 IoFileObjectType,
2472 UserMode,
2473 (PVOID*)&FileObject,
2474 NULL);
2475 if (!NT_SUCCESS(Status))
2476 {
2477 return Status;
2478 }
2479
2480 /*
2481 * Initialized caching for this file object if previously caching
2482 * was initialized for the same on disk file
2483 */
2484 Status = CcTryToInitializeFileCache(FileObject);
2485
2486 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
2487 {
2488 /*
2489 * Read the dos header and check the DOS signature
2490 */
2491 Offset.QuadPart = 0;
2492 Status = ZwReadFile(FileHandle,
2493 NULL,
2494 NULL,
2495 NULL,
2496 &Iosb,
2497 &DosHeader,
2498 sizeof(DosHeader),
2499 &Offset,
2500 0);
2501 if (!NT_SUCCESS(Status))
2502 {
2503 ObDereferenceObject(FileObject);
2504 return(Status);
2505 }
2506
2507 /*
2508 * Check the DOS signature
2509 */
2510 if (Iosb.Information != sizeof(DosHeader) ||
2511 DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2512 {
2513 ObDereferenceObject(FileObject);
2514 return(STATUS_INVALID_IMAGE_FORMAT);
2515 }
2516
2517 /*
2518 * Read the PE header
2519 */
2520 Offset.QuadPart = DosHeader.e_lfanew;
2521 Status = ZwReadFile(FileHandle,
2522 NULL,
2523 NULL,
2524 NULL,
2525 &Iosb,
2526 &PEHeader,
2527 sizeof(PEHeader),
2528 &Offset,
2529 0);
2530 if (!NT_SUCCESS(Status))
2531 {
2532 ObDereferenceObject(FileObject);
2533 return(Status);
2534 }
2535
2536 /*
2537 * Check the signature
2538 */
2539 if (Iosb.Information != sizeof(PEHeader) ||
2540 PEHeader.Signature != IMAGE_NT_SIGNATURE)
2541 {
2542 ObDereferenceObject(FileObject);
2543 return(STATUS_INVALID_IMAGE_FORMAT);
2544 }
2545
2546 /*
2547 * Read in the section headers
2548 */
2549 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2550 ImageSections = ExAllocatePool(NonPagedPool,
2551 PEHeader.FileHeader.NumberOfSections *
2552 sizeof(IMAGE_SECTION_HEADER));
2553 if (ImageSections == NULL)
2554 {
2555 ObDereferenceObject(FileObject);
2556 return(STATUS_NO_MEMORY);
2557 }
2558
2559 Status = ZwReadFile(FileHandle,
2560 NULL,
2561 NULL,
2562 NULL,
2563 &Iosb,
2564 ImageSections,
2565 PEHeader.FileHeader.NumberOfSections *
2566 sizeof(IMAGE_SECTION_HEADER),
2567 &Offset,
2568 0);
2569 if (!NT_SUCCESS(Status))
2570 {
2571 ObDereferenceObject(FileObject);
2572 ExFreePool(ImageSections);
2573 return(Status);
2574 }
2575 if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2576 {
2577 ObDereferenceObject(FileObject);
2578 ExFreePool(ImageSections);
2579 return(STATUS_INVALID_IMAGE_FORMAT);
2580 }
2581
2582 /*
2583 * Create the section
2584 */
2585 Status = ObRosCreateObject(SectionHandle,
2586 DesiredAccess,
2587 ObjectAttributes,
2588 MmSectionObjectType,
2589 (PVOID*)&Section);
2590 if (!NT_SUCCESS(Status))
2591 {
2592 ObDereferenceObject(FileObject);
2593 ExFreePool(ImageSections);
2594 return(Status);
2595 }
2596
2597 /*
2598 * Initialize it
2599 */
2600 Section->SectionPageProtection = SectionPageProtection;
2601 Section->AllocationAttributes = AllocationAttributes;
2602 InitializeListHead(&Section->ViewListHead);
2603 KeInitializeSpinLock(&Section->ViewListLock);
2604
2605 /*
2606 * Check file access required
2607 */
2608 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2609 {
2610 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2611 }
2612 else
2613 {
2614 FileAccess = FILE_READ_DATA;
2615 }
2616
2617 /*
2618 * We can't do memory mappings if the file system doesn't support the
2619 * standard FCB
2620 */
2621 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2622 {
2623 ZwClose(*SectionHandle);
2624 ObDereferenceObject(Section);
2625 ObDereferenceObject(FileObject);
2626 ExFreePool(ImageSections);
2627 return(STATUS_INVALID_FILE_FOR_SECTION);
2628 }
2629
2630 /*
2631 * Lock the file
2632 */
2633 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2634 0,
2635 KernelMode,
2636 FALSE,
2637 NULL);
2638 if (Status != STATUS_SUCCESS)
2639 {
2640 ZwClose(*SectionHandle);
2641 ObDereferenceObject(Section);
2642 ObDereferenceObject(FileObject);
2643 ExFreePool(ImageSections);
2644 return(Status);
2645 }
2646
2647 /*
2648 * allocate the section segments to describe the mapping
2649 */
2650 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2651 Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
2652 ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2653 if (ImageSectionObject == NULL)
2654 {
2655 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2656 ZwClose(*SectionHandle);
2657 ObDereferenceObject(Section);
2658 ObDereferenceObject(FileObject);
2659 ExFreePool(ImageSections);
2660 return(STATUS_NO_MEMORY);
2661 }
2662 Section->ImageSection = ImageSectionObject;
2663 ImageSectionObject->NrSegments = NrSegments;
2664 ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2665 ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2666 ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2667 ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2668 ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
2669 ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
2670 ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
2671 ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2672 ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
2673 ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2674
2675 SectionSegments = ImageSectionObject->Segments;
2676 SectionSegments[0].FileOffset = 0;
2677 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2678 SectionSegments[0].Protection = PAGE_READONLY;
2679 SectionSegments[0].RawLength = PAGE_SIZE;
2680 SectionSegments[0].Length = PAGE_SIZE;
2681 SectionSegments[0].Flags = 0;
2682 SectionSegments[0].ReferenceCount = 1;
2683 SectionSegments[0].VirtualAddress = 0;
2684 SectionSegments[0].WriteCopy = FALSE;
2685 ExInitializeFastMutex(&SectionSegments[0].Lock);
2686 for (i = 1; i < NrSegments; i++)
2687 {
2688 SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
2689 SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
2690
2691 /*
2692 * Set up the protection and write copy variables.
2693 */
2694 Characteristics = ImageSections[i - 1].Characteristics;
2695 if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
2696 {
2697 SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
2698 SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2699 }
2700 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2701 {
2702 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2703 SectionSegments[i].WriteCopy = TRUE;
2704 }
2705 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2706 {
2707 SectionSegments[i].Protection = PAGE_READWRITE;
2708 SectionSegments[i].WriteCopy = TRUE;
2709 }
2710 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2711 {
2712 SectionSegments[i].Protection = PAGE_READWRITE;
2713 SectionSegments[i].WriteCopy = TRUE;
2714 }
2715 else
2716 {
2717 SectionSegments[i].Protection = PAGE_NOACCESS;
2718 SectionSegments[i].WriteCopy = TRUE;
2719 }
2720
2721 /*
2722 * Set up the attributes.
2723 */
2724 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2725 {
2726 SectionSegments[i].Attributes = 0;
2727 }
2728 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2729 {
2730 SectionSegments[i].Attributes = 0;
2731 }
2732 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2733 {
2734 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2735 }
2736 else
2737 {
2738 SectionSegments[i].Attributes = 0;
2739 }
2740
2741 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2742 SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
2743 SectionSegments[i].Flags = 0;
2744 SectionSegments[i].ReferenceCount = 1;
2745 SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
2746 ExInitializeFastMutex(&SectionSegments[i].Lock);
2747 }
2748 if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
2749 (LONG)ImageSectionObject, 0))
2750 {
2751 /*
2752 * An other thread has initialized the some image in the background
2753 */
2754 ExFreePool(ImageSectionObject);
2755 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2756 Section->ImageSection = ImageSectionObject;
2757 SectionSegments = ImageSectionObject->Segments;
2758
2759 for (i = 0; i < NrSegments; i++)
2760 {
2761 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2762 }
2763 }
2764 ExFreePool(ImageSections);
2765 }
2766 else
2767 {
2768 /*
2769 * Create the section
2770 */
2771 Status = ObRosCreateObject(SectionHandle,
2772 DesiredAccess,
2773 ObjectAttributes,
2774 MmSectionObjectType,
2775 (PVOID*)&Section);
2776 if (!NT_SUCCESS(Status))
2777 {
2778 ObDereferenceObject(FileObject);
2779 return(Status);
2780 }
2781
2782 /*
2783 * Initialize it
2784 */
2785 Section->SectionPageProtection = SectionPageProtection;
2786 Section->AllocationAttributes = AllocationAttributes;
2787 InitializeListHead(&Section->ViewListHead);
2788 KeInitializeSpinLock(&Section->ViewListLock);
2789
2790 /*
2791 * Check file access required
2792 */
2793 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2794 {
2795 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2796 }
2797 else
2798 {
2799 FileAccess = FILE_READ_DATA;
2800 }
2801
2802 /*
2803 * Lock the file
2804 */
2805 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2806 0,
2807 KernelMode,
2808 FALSE,
2809 NULL);
2810 if (Status != STATUS_SUCCESS)
2811 {
2812 ZwClose(*SectionHandle);
2813 ObDereferenceObject(Section);
2814 ObDereferenceObject(FileObject);
2815 return(Status);
2816 }
2817
2818 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2819 Section->ImageSection = ImageSectionObject;
2820 SectionSegments = ImageSectionObject->Segments;
2821 NrSegments = ImageSectionObject->NrSegments;
2822
2823 /*
2824 * Otherwise just reference all the section segments
2825 */
2826 for (i = 0; i < NrSegments; i++)
2827 {
2828 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2829 }
2830
2831 }
2832 Section->FileObject = FileObject;
2833 CcRosReferenceCache(FileObject);
2834 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2835 ObDereferenceObject(Section);
2836 return(STATUS_SUCCESS);
2837 }
2838
2839 /*
2840 * @implemented
2841 */
2842 NTSTATUS STDCALL
2843 NtCreateSection (OUT PHANDLE SectionHandle,
2844 IN ACCESS_MASK DesiredAccess,
2845 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2846 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2847 IN ULONG SectionPageProtection OPTIONAL,
2848 IN ULONG AllocationAttributes,
2849 IN HANDLE FileHandle OPTIONAL)
2850 {
2851 if (AllocationAttributes & SEC_IMAGE)
2852 {
2853 return(MmCreateImageSection(SectionHandle,
2854 DesiredAccess,
2855 ObjectAttributes,
2856 MaximumSize,
2857 SectionPageProtection,
2858 AllocationAttributes,
2859 FileHandle));
2860 }
2861 else if (FileHandle != NULL)
2862 {
2863 return(MmCreateDataFileSection(SectionHandle,
2864 DesiredAccess,
2865 ObjectAttributes,
2866 MaximumSize,
2867 SectionPageProtection,
2868 AllocationAttributes,
2869 FileHandle));
2870 }
2871 else
2872 {
2873 return(MmCreatePageFileSection(SectionHandle,
2874 DesiredAccess,
2875 ObjectAttributes,
2876 MaximumSize,
2877 SectionPageProtection,
2878 AllocationAttributes));
2879 }
2880 }
2881
2882
2883 /**********************************************************************
2884 * NAME
2885 * NtOpenSection
2886 *
2887 * DESCRIPTION
2888 *
2889 * ARGUMENTS
2890 * SectionHandle
2891 *
2892 * DesiredAccess
2893 *
2894 * ObjectAttributes
2895 *
2896 * RETURN VALUE
2897 *
2898 * REVISIONS
2899 */
2900 NTSTATUS STDCALL
2901 NtOpenSection(PHANDLE SectionHandle,
2902 ACCESS_MASK DesiredAccess,
2903 POBJECT_ATTRIBUTES ObjectAttributes)
2904 {
2905 NTSTATUS Status;
2906
2907 *SectionHandle = 0;
2908
2909 Status = ObOpenObjectByName(ObjectAttributes,
2910 MmSectionObjectType,
2911 NULL,
2912 UserMode,
2913 DesiredAccess,
2914 NULL,
2915 SectionHandle);
2916
2917 return(Status);
2918 }
2919
2920 NTSTATUS STATIC
2921 MmMapViewOfSegment(PEPROCESS Process,
2922 PMADDRESS_SPACE AddressSpace,
2923 PSECTION_OBJECT Section,
2924 PMM_SECTION_SEGMENT Segment,
2925 PVOID* BaseAddress,
2926 ULONG ViewSize,
2927 ULONG Protect,
2928 ULONG ViewOffset,
2929 BOOL TopDown)
2930 {
2931 PMEMORY_AREA MArea;
2932 NTSTATUS Status;
2933 KIRQL oldIrql;
2934
2935 Status = MmCreateMemoryArea(Process,
2936 AddressSpace,
2937 MEMORY_AREA_SECTION_VIEW,
2938 BaseAddress,
2939 ViewSize,
2940 Protect,
2941 &MArea,
2942 FALSE,
2943 TopDown);
2944 if (!NT_SUCCESS(Status))
2945 {
2946 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2947 (*BaseAddress), (*BaseAddress) + ViewSize);
2948 return(Status);
2949 }
2950
2951 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2952 InsertTailList(&Section->ViewListHead,
2953 &MArea->Data.SectionData.ViewListEntry);
2954 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2955
2956 ObReferenceObjectByPointer((PVOID)Section,
2957 SECTION_MAP_READ,
2958 NULL,
2959 ExGetPreviousMode());
2960 MArea->Data.SectionData.Segment = Segment;
2961 MArea->Data.SectionData.Section = Section;
2962 MArea->Data.SectionData.ViewOffset = ViewOffset;
2963 MArea->Data.SectionData.WriteCopyView = FALSE;
2964 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
2965 ViewSize, 0, Protect);
2966
2967 return(STATUS_SUCCESS);
2968 }
2969
2970
2971 /**********************************************************************
2972 * NAME EXPORTED
2973 * NtMapViewOfSection
2974 *
2975 * DESCRIPTION
2976 * Maps a view of a section into the virtual address space of a
2977 * process.
2978 *
2979 * ARGUMENTS
2980 * SectionHandle
2981 * Handle of the section.
2982 *
2983 * ProcessHandle
2984 * Handle of the process.
2985 *
2986 * BaseAddress
2987 * Desired base address (or NULL) on entry;
2988 * Actual base address of the view on exit.
2989 *
2990 * ZeroBits
2991 * Number of high order address bits that must be zero.
2992 *
2993 * CommitSize
2994 * Size in bytes of the initially committed section of
2995 * the view.
2996 *
2997 * SectionOffset
2998 * Offset in bytes from the beginning of the section
2999 * to the beginning of the view.
3000 *
3001 * ViewSize
3002 * Desired length of map (or zero to map all) on entry
3003 * Actual length mapped on exit.
3004 *
3005 * InheritDisposition
3006 * Specified how the view is to be shared with
3007 * child processes.
3008 *
3009 * AllocateType
3010 * Type of allocation for the pages.
3011 *
3012 * Protect
3013 * Protection for the committed region of the view.
3014 *
3015 * RETURN VALUE
3016 * Status.
3017 *
3018 * @implemented
3019 */
3020 NTSTATUS STDCALL
3021 NtMapViewOfSection(HANDLE SectionHandle,
3022 HANDLE ProcessHandle,
3023 PVOID* BaseAddress,
3024 ULONG ZeroBits,
3025 ULONG CommitSize,
3026 PLARGE_INTEGER SectionOffset,
3027 PULONG ViewSize,
3028 SECTION_INHERIT InheritDisposition,
3029 ULONG AllocationType,
3030 ULONG Protect)
3031 {
3032 PSECTION_OBJECT Section;
3033 PEPROCESS Process;
3034 NTSTATUS Status;
3035 PMADDRESS_SPACE AddressSpace;
3036
3037 Status = ObReferenceObjectByHandle(ProcessHandle,
3038 PROCESS_VM_OPERATION,
3039 PsProcessType,
3040 UserMode,
3041 (PVOID*)&Process,
3042 NULL);
3043 if (!NT_SUCCESS(Status))
3044 {
3045 return(Status);
3046 }
3047
3048 AddressSpace = &Process->AddressSpace;
3049
3050 Status = ObReferenceObjectByHandle(SectionHandle,
3051 SECTION_MAP_READ,
3052 MmSectionObjectType,
3053 UserMode,
3054 (PVOID*)&Section,
3055 NULL);
3056 if (!(NT_SUCCESS(Status)))
3057 {
3058 DPRINT("ObReference failed rc=%x\n",Status);
3059 ObDereferenceObject(Process);
3060 return(Status);
3061 }
3062
3063 Status = MmMapViewOfSection(Section,
3064 Process,
3065 BaseAddress,
3066 ZeroBits,
3067 CommitSize,
3068 SectionOffset,
3069 ViewSize,
3070 InheritDisposition,
3071 AllocationType,
3072 Protect);
3073
3074 ObDereferenceObject(Section);
3075 ObDereferenceObject(Process);
3076
3077 return(Status);
3078 }
3079
3080 VOID STATIC
3081 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3082 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
3083 BOOLEAN Dirty)
3084 {
3085 PMEMORY_AREA MArea;
3086 ULONG Entry;
3087 PFILE_OBJECT FileObject;
3088 PBCB Bcb;
3089 ULONG Offset;
3090 SWAPENTRY SavedSwapEntry;
3091 PMM_PAGEOP PageOp;
3092 LARGE_INTEGER Timeout;
3093 NTSTATUS Status;
3094 PSECTION_OBJECT Section;
3095 PMM_SECTION_SEGMENT Segment;
3096
3097 MArea = (PMEMORY_AREA)Context;
3098
3099 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3100
3101 Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress);
3102
3103 Section = MArea->Data.SectionData.Section;
3104 Segment = MArea->Data.SectionData.Segment;
3105
3106
3107 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3108
3109 while (PageOp)
3110 {
3111 MmUnlockSectionSegment(Segment);
3112 MmUnlockAddressSpace(&MArea->Process->AddressSpace);
3113
3114 Timeout.QuadPart = -100000000LL; // 10 sec
3115 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
3116 0,
3117 KernelMode,
3118 FALSE,
3119 &Timeout);
3120 if (Status != STATUS_SUCCESS)
3121 {
3122 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3123 KeBugCheck(0);
3124 }
3125
3126 MmLockAddressSpace(&MArea->Process->AddressSpace);
3127 MmLockSectionSegment(Segment);
3128 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
3129 MmReleasePageOp(PageOp);
3130 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3131 }
3132
3133 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3134
3135 /*
3136 * For a dirty, datafile, non-private page mark it as dirty in the
3137 * cache manager.
3138 */
3139 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3140 {
3141 if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
3142 {
3143 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3144 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3145 CcRosMarkDirtyCacheSegment(Bcb, Offset);
3146 assert(SwapEntry == 0);
3147 }
3148 }
3149
3150 if (SwapEntry != 0)
3151 {
3152 MmFreeSwapPage(SwapEntry);
3153 }
3154 else if (PhysAddr.QuadPart != 0)
3155 {
3156 if (IS_SWAP_FROM_SSE(Entry) ||
3157 PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
3158 {
3159 /*
3160 * Just dereference private pages
3161 */
3162 SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
3163 if (SavedSwapEntry != 0)
3164 {
3165 MmFreeSwapPage(SavedSwapEntry);
3166 MmSetSavedSwapEntryPage(PhysAddr, 0);
3167 }
3168 MmDeleteRmap(PhysAddr, MArea->Process, Address);
3169 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3170 }
3171 else
3172 {
3173 MmDeleteRmap(PhysAddr, MArea->Process, Address);
3174 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty);
3175 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3176 }
3177 }
3178 }
3179
3180 /*
3181 * @implemented
3182 */
3183 NTSTATUS STDCALL
3184 MmUnmapViewOfSection(PEPROCESS Process,
3185 PVOID BaseAddress)
3186 {
3187 NTSTATUS Status;
3188 PMEMORY_AREA MemoryArea;
3189 PMADDRESS_SPACE AddressSpace;
3190 PSECTION_OBJECT Section;
3191 PMM_SECTION_SEGMENT Segment;
3192 KIRQL oldIrql;
3193 PLIST_ENTRY CurrentEntry;
3194 PMM_REGION CurrentRegion;
3195
3196 assert(Process);
3197
3198 AddressSpace = &Process->AddressSpace;
3199
3200 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3201 Process, BaseAddress);
3202 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3203 BaseAddress);
3204 if (MemoryArea == NULL)
3205 {
3206 return(STATUS_UNSUCCESSFUL);
3207 }
3208
3209 MemoryArea->DeleteInProgress = TRUE;
3210 Section = MemoryArea->Data.SectionData.Section;
3211 Segment = MemoryArea->Data.SectionData.Segment;
3212
3213 MmLockSectionSegment(Segment);
3214 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3215 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3216 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3217
3218 CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink;
3219 while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead)
3220 {
3221 CurrentRegion =
3222 CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3223 CurrentEntry = CurrentEntry->Flink;
3224 ExFreePool(CurrentRegion);
3225 }
3226
3227 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3228 {
3229 Status = MmFreeMemoryArea(&Process->AddressSpace,
3230 BaseAddress,
3231 0,
3232 NULL,
3233 NULL);
3234 }
3235 else
3236 {
3237 Status = MmFreeMemoryArea(&Process->AddressSpace,
3238 BaseAddress,
3239 0,
3240 MmFreeSectionPage,
3241 MemoryArea);
3242 }
3243 MmUnlockSectionSegment(Segment);
3244 ObDereferenceObject(Section);
3245 return(STATUS_SUCCESS);
3246 }
3247
3248 /**********************************************************************
3249 * NAME EXPORTED
3250 * NtUnmapViewOfSection
3251 *
3252 * DESCRIPTION
3253 *
3254 * ARGUMENTS
3255 * ProcessHandle
3256 *
3257 * BaseAddress
3258 *
3259 * RETURN VALUE
3260 * Status.
3261 *
3262 * REVISIONS
3263 */
3264 NTSTATUS STDCALL
3265 NtUnmapViewOfSection (HANDLE ProcessHandle,
3266 PVOID BaseAddress)
3267 {
3268 PEPROCESS Process;
3269 NTSTATUS Status;
3270
3271 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3272 ProcessHandle, BaseAddress);
3273
3274 DPRINT("Referencing process\n");
3275 Status = ObReferenceObjectByHandle(ProcessHandle,
3276 PROCESS_VM_OPERATION,
3277 PsProcessType,
3278 UserMode,
3279 (PVOID*)&Process,
3280 NULL);
3281 if (!NT_SUCCESS(Status))
3282 {
3283 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3284 return(Status);
3285 }
3286
3287 MmLockAddressSpace(&Process->AddressSpace);
3288 Status = MmUnmapViewOfSection(Process, BaseAddress);
3289 MmUnlockAddressSpace(&Process->AddressSpace);
3290
3291 ObDereferenceObject(Process);
3292
3293 return Status;
3294 }
3295
3296
3297 NTSTATUS STDCALL
3298 NtQuerySection (IN HANDLE SectionHandle,
3299 IN CINT SectionInformationClass,
3300 OUT PVOID SectionInformation,
3301 IN ULONG Length,
3302 OUT PULONG ResultLength)
3303 /*
3304 * FUNCTION: Queries the information of a section object.
3305 * ARGUMENTS:
3306 * SectionHandle = Handle to the section link object
3307 * SectionInformationClass = Index to a certain information structure
3308 * SectionInformation (OUT)= Caller supplies storage for resulting
3309 * information
3310 * Length = Size of the supplied storage
3311 * ResultLength = Data written
3312 * RETURNS: Status
3313 *
3314 */
3315 {
3316 PSECTION_OBJECT Section;
3317 NTSTATUS Status;
3318
3319 Status = ObReferenceObjectByHandle(SectionHandle,
3320 SECTION_MAP_READ,
3321 MmSectionObjectType,
3322 UserMode,
3323 (PVOID*)&Section,
3324 NULL);
3325 if (!(NT_SUCCESS(Status)))
3326 {
3327 return(Status);
3328 }
3329
3330 switch (SectionInformationClass)
3331 {
3332 case SectionBasicInformation:
3333 {
3334 PSECTION_BASIC_INFORMATION Sbi;
3335
3336 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3337 {
3338 ObDereferenceObject(Section);
3339 return(STATUS_INFO_LENGTH_MISMATCH);
3340 }
3341
3342 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3343
3344 Sbi->BaseAddress = 0;
3345 Sbi->Attributes = 0;
3346 Sbi->Size.QuadPart = 0;
3347
3348 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3349 Status = STATUS_SUCCESS;
3350 break;
3351 }
3352
3353 case SectionImageInformation:
3354 {
3355 PSECTION_IMAGE_INFORMATION Sii;
3356
3357 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3358 {
3359 ObDereferenceObject(Section);
3360 return(STATUS_INFO_LENGTH_MISMATCH);
3361 }
3362
3363 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3364 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
3365 if (Section->AllocationAttributes & SEC_IMAGE)
3366 {
3367 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3368 ImageSectionObject = Section->ImageSection;
3369
3370 Sii->EntryPoint = ImageSectionObject->EntryPoint;
3371 Sii->StackReserve = ImageSectionObject->StackReserve;
3372 Sii->StackCommit = ImageSectionObject->StackCommit;
3373 Sii->Subsystem = ImageSectionObject->Subsystem;
3374 Sii->MinorSubsystemVersion = ImageSectionObject->MinorSubsystemVersion;
3375 Sii->MajorSubsystemVersion = ImageSectionObject->MajorSubsystemVersion;
3376 Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
3377 Sii->ImageNumber = ImageSectionObject->Machine;
3378 Sii->Executable = ImageSectionObject->Executable;
3379 }
3380 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3381 Status = STATUS_SUCCESS;
3382 break;
3383 }
3384
3385 default:
3386 *ResultLength = 0;
3387 Status = STATUS_INVALID_INFO_CLASS;
3388 }
3389 ObDereferenceObject(Section);
3390 return(Status);
3391 }
3392
3393
3394 NTSTATUS STDCALL
3395 NtExtendSection(IN HANDLE SectionHandle,
3396 IN ULONG NewMaximumSize)
3397 {
3398 UNIMPLEMENTED;
3399 return(STATUS_NOT_IMPLEMENTED);
3400 }
3401
3402
3403 /**********************************************************************
3404 * NAME INTERNAL
3405 * MmAllocateSection@4
3406 *
3407 * DESCRIPTION
3408 *
3409 * ARGUMENTS
3410 * Length
3411 *
3412 * RETURN VALUE
3413 *
3414 * NOTE
3415 * Code taken from ntoskrnl/mm/special.c.
3416 *
3417 * REVISIONS
3418 */
3419 PVOID STDCALL
3420 MmAllocateSection (IN ULONG Length)
3421 {
3422 PVOID Result;
3423 MEMORY_AREA* marea;
3424 NTSTATUS Status;
3425 ULONG i;
3426 PMADDRESS_SPACE AddressSpace;
3427
3428 DPRINT("MmAllocateSection(Length %x)\n",Length);
3429
3430 AddressSpace = MmGetKernelAddressSpace();
3431 Result = NULL;
3432 MmLockAddressSpace(AddressSpace);
3433 Status = MmCreateMemoryArea (NULL,
3434 AddressSpace,
3435 MEMORY_AREA_SYSTEM,
3436 &Result,
3437 Length,
3438 0,
3439 &marea,
3440 FALSE,
3441 FALSE);
3442 if (!NT_SUCCESS(Status))
3443 {
3444 MmUnlockAddressSpace(AddressSpace);
3445 return (NULL);
3446 }
3447 MmUnlockAddressSpace(AddressSpace);
3448 DPRINT("Result %p\n",Result);
3449 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3450 {
3451 PHYSICAL_ADDRESS Page;
3452
3453 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3454 if (!NT_SUCCESS(Status))
3455 {
3456 DbgPrint("Unable to allocate page\n");
3457 KeBugCheck(0);
3458 }
3459 Status = MmCreateVirtualMapping (NULL,
3460 (Result + (i * PAGE_SIZE)),
3461 PAGE_READWRITE,
3462 Page,
3463 TRUE);
3464 if (!NT_SUCCESS(Status))
3465 {
3466 DbgPrint("Unable to create virtual mapping\n");
3467 KeBugCheck(0);
3468 }
3469 }
3470 return ((PVOID)Result);
3471 }
3472
3473
3474 /**********************************************************************
3475 * NAME EXPORTED
3476 * MmMapViewOfSection
3477 *
3478 * DESCRIPTION
3479 * Maps a view of a section into the virtual address space of a
3480 * process.
3481 *
3482 * ARGUMENTS
3483 * Section
3484 * Pointer to the section object.
3485 *
3486 * ProcessHandle
3487 * Pointer to the process.
3488 *
3489 * BaseAddress
3490 * Desired base address (or NULL) on entry;
3491 * Actual base address of the view on exit.
3492 *
3493 * ZeroBits
3494 * Number of high order address bits that must be zero.
3495 *
3496 * CommitSize
3497 * Size in bytes of the initially committed section of
3498 * the view.
3499 *
3500 * SectionOffset
3501 * Offset in bytes from the beginning of the section
3502 * to the beginning of the view.
3503 *
3504 * ViewSize
3505 * Desired length of map (or zero to map all) on entry
3506 * Actual length mapped on exit.
3507 *
3508 * InheritDisposition
3509 * Specified how the view is to be shared with
3510 * child processes.
3511 *
3512 * AllocationType
3513 * Type of allocation for the pages.
3514 *
3515 * Protect
3516 * Protection for the committed region of the view.
3517 *
3518 * RETURN VALUE
3519 * Status.
3520 *
3521 * @implemented
3522 */
3523 NTSTATUS STDCALL
3524 MmMapViewOfSection(IN PVOID SectionObject,
3525 IN PEPROCESS Process,
3526 IN OUT PVOID *BaseAddress,
3527 IN ULONG ZeroBits,
3528 IN ULONG CommitSize,
3529 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3530 IN OUT PULONG ViewSize,
3531 IN SECTION_INHERIT InheritDisposition,
3532 IN ULONG AllocationType,
3533 IN ULONG Protect)
3534 {
3535 PSECTION_OBJECT Section;
3536 PMADDRESS_SPACE AddressSpace;
3537 ULONG ViewOffset;
3538 NTSTATUS Status = STATUS_SUCCESS;
3539
3540 assert(Process);
3541
3542 Section = (PSECTION_OBJECT)SectionObject;
3543 AddressSpace = &Process->AddressSpace;
3544
3545 MmLockAddressSpace(AddressSpace);
3546
3547 if (Section->AllocationAttributes & SEC_IMAGE)
3548 {
3549 ULONG i;
3550 ULONG NrSegments;
3551 PVOID ImageBase;
3552 ULONG ImageSize;
3553 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3554 PMM_SECTION_SEGMENT SectionSegments;
3555
3556 ImageSectionObject = Section->ImageSection;
3557 SectionSegments = ImageSectionObject->Segments;
3558 NrSegments = ImageSectionObject->NrSegments;
3559
3560
3561 ImageBase = *BaseAddress;
3562 if (ImageBase == NULL)
3563 {
3564 ImageBase = ImageSectionObject->ImageBase;
3565 }
3566
3567 ImageSize = 0;
3568 for (i = 0; i < NrSegments; i++)
3569 {
3570 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3571 {
3572 ULONG MaxExtent;
3573 MaxExtent = (ULONG)(SectionSegments[i].VirtualAddress +
3574 SectionSegments[i].Length);
3575 ImageSize = max(ImageSize, MaxExtent);
3576 }
3577 }
3578
3579 /* Check there is enough space to map the section at that point. */
3580 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3581 PAGE_ROUND_UP(ImageSize)) != NULL)
3582 {
3583 /* Fail if the user requested a fixed base address. */
3584 if ((*BaseAddress) != NULL)
3585 {
3586 MmUnlockAddressSpace(AddressSpace);
3587 return(STATUS_UNSUCCESSFUL);
3588 }
3589 /* Otherwise find a gap to map the image. */
3590 ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE);
3591 if (ImageBase == NULL)
3592 {
3593 MmUnlockAddressSpace(AddressSpace);
3594 return(STATUS_UNSUCCESSFUL);
3595 }
3596 }
3597
3598 for (i = 0; i < NrSegments; i++)
3599 {
3600 PVOID SBaseAddress;
3601
3602 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3603 {
3604 SBaseAddress = (PVOID)
3605 (ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3606 MmLockSectionSegment(&SectionSegments[i]);
3607 Status = MmMapViewOfSegment(Process,
3608 AddressSpace,
3609 Section,
3610 &SectionSegments[i],
3611 &SBaseAddress,
3612 SectionSegments[i].Length,
3613 SectionSegments[i].Protection,
3614 (ULONG_PTR)SectionSegments[i].VirtualAddress,
3615 FALSE);
3616 MmUnlockSectionSegment(&SectionSegments[i]);
3617 if (!NT_SUCCESS(Status))
3618 {
3619 MmUnlockAddressSpace(AddressSpace);
3620 return(Status);
3621 }
3622 }
3623 }
3624
3625 *BaseAddress = ImageBase;
3626 }
3627 else
3628 {
3629 if (SectionOffset == NULL)
3630 {
3631 ViewOffset = 0;
3632 }
3633 else
3634 {
3635 ViewOffset = SectionOffset->u.LowPart;
3636 }
3637
3638 if ((ViewOffset % PAGE_SIZE) != 0)
3639 {
3640 MmUnlockAddressSpace(AddressSpace);
3641 return(STATUS_MAPPED_ALIGNMENT);
3642 }
3643
3644 if ((*ViewSize) == 0)
3645 {
3646 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3647 }
3648 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3649 {
3650 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3651 }
3652
3653 MmLockSectionSegment(Section->Segment);
3654 Status = MmMapViewOfSegment(Process,
3655 AddressSpace,
3656 Section,
3657 Section->Segment,
3658 BaseAddress,
3659 *ViewSize,
3660 Protect,
3661 ViewOffset,
3662 (AllocationType & MEM_TOP_DOWN));
3663 MmUnlockSectionSegment(Section->Segment);
3664 if (!NT_SUCCESS(Status))
3665 {
3666 MmUnlockAddressSpace(AddressSpace);
3667 return(Status);
3668 }
3669 }
3670
3671 MmUnlockAddressSpace(AddressSpace);
3672
3673 return(STATUS_SUCCESS);
3674 }
3675
3676 /*
3677 * @unimplemented
3678 */
3679 BOOLEAN STDCALL
3680 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3681 IN PLARGE_INTEGER NewFileSize)
3682 {
3683 UNIMPLEMENTED;
3684 return (FALSE);
3685 }
3686
3687
3688 /*
3689 * @unimplemented
3690 */
3691 BOOLEAN STDCALL
3692 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3693 {
3694 UNIMPLEMENTED;
3695 return (FALSE);
3696 }
3697
3698 /*
3699 * @implemented
3700 */
3701 BOOLEAN STDCALL
3702 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3703 IN MMFLUSH_TYPE FlushType)
3704 {
3705 switch(FlushType)
3706 {
3707 case MmFlushForDelete:
3708 if (SectionObjectPointer->ImageSectionObject ||
3709 SectionObjectPointer->DataSectionObject)
3710 {
3711 return FALSE;
3712 }
3713 CcRosSetRemoveOnClose(SectionObjectPointer);
3714 return TRUE;
3715 case MmFlushForWrite:
3716 break;
3717 }
3718 return FALSE;
3719 }
3720
3721 /*
3722 * @unimplemented
3723 */
3724 BOOLEAN STDCALL
3725 MmForceSectionClosed (DWORD Unknown0,
3726 DWORD Unknown1)
3727 {
3728 UNIMPLEMENTED;
3729 return (FALSE);
3730 }
3731
3732
3733 /*
3734 * @implemented
3735 */
3736 NTSTATUS STDCALL
3737 MmMapViewInSystemSpace (IN PVOID SectionObject,
3738 OUT PVOID * MappedBase,
3739 IN OUT PULONG ViewSize)
3740 {
3741 PSECTION_OBJECT Section;
3742 PMADDRESS_SPACE AddressSpace;
3743 NTSTATUS Status;
3744
3745 DPRINT("MmMapViewInSystemSpace() called\n");
3746
3747 Section = (PSECTION_OBJECT)SectionObject;
3748 AddressSpace = MmGetKernelAddressSpace();
3749
3750 MmLockAddressSpace(AddressSpace);
3751
3752
3753 if ((*ViewSize) == 0)
3754 {
3755 (*ViewSize) = Section->MaximumSize.u.LowPart;
3756 }
3757 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
3758 {
3759 (*ViewSize) = Section->MaximumSize.u.LowPart;
3760 }
3761
3762 MmLockSectionSegment(Section->Segment);
3763
3764
3765 Status = MmMapViewOfSegment(NULL,
3766 AddressSpace,
3767 Section,
3768 Section->Segment,
3769 MappedBase,
3770 *ViewSize,
3771 PAGE_READWRITE,
3772 0,
3773 FALSE);
3774
3775 MmUnlockSectionSegment(Section->Segment);
3776 MmUnlockAddressSpace(AddressSpace);
3777
3778 return Status;
3779 }
3780
3781
3782 /*
3783 * @implemented
3784 */
3785 NTSTATUS STDCALL
3786 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
3787 {
3788 PMEMORY_AREA MemoryArea;
3789 PMADDRESS_SPACE AddressSpace;
3790 PSECTION_OBJECT Section;
3791 PMM_SECTION_SEGMENT Segment;
3792 KIRQL oldIrql;
3793 PLIST_ENTRY CurrentEntry;
3794 PMM_REGION CurrentRegion;
3795 NTSTATUS Status;
3796
3797 DPRINT("MmUnmapViewInSystemSpace() called\n");
3798
3799 AddressSpace = MmGetKernelAddressSpace();
3800
3801 DPRINT("Opening memory area at base address %x\n",
3802 MappedBase);
3803 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3804 MappedBase);
3805 if (MemoryArea == NULL)
3806 {
3807 return STATUS_UNSUCCESSFUL;
3808 }
3809
3810 MemoryArea->DeleteInProgress = TRUE;
3811 Section = MemoryArea->Data.SectionData.Section;
3812 Segment = MemoryArea->Data.SectionData.Segment;
3813
3814 MmLockSectionSegment(Segment);
3815 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3816 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3817 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3818
3819 CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink;
3820 while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead)
3821 {
3822 CurrentRegion =
3823 CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3824 CurrentEntry = CurrentEntry->Flink;
3825 ExFreePool(CurrentRegion);
3826 }
3827
3828 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3829 {
3830 Status = MmFreeMemoryArea(AddressSpace,
3831 MappedBase,
3832 0,
3833 NULL,
3834 NULL);
3835 }
3836 else
3837 {
3838 Status = MmFreeMemoryArea(AddressSpace,
3839 MappedBase,
3840 0,
3841 MmFreeSectionPage,
3842 MemoryArea);
3843 }
3844
3845 MmUnlockSectionSegment(Segment);
3846 ObDereferenceObject(Section);
3847
3848 return(STATUS_SUCCESS);
3849 }
3850
3851
3852 /*
3853 * @unimplemented
3854 */
3855 NTSTATUS STDCALL
3856 MmSetBankedSection (DWORD Unknown0,
3857 DWORD Unknown1,
3858 DWORD Unknown2,
3859 DWORD Unknown3,
3860 DWORD Unknown4,
3861 DWORD Unknown5)
3862 {
3863 UNIMPLEMENTED;
3864 return (STATUS_NOT_IMPLEMENTED);
3865 }
3866
3867
3868 /**********************************************************************
3869 * NAME EXPORTED
3870 * MmCreateSection@
3871 *
3872 * DESCRIPTION
3873 * Creates a section object.
3874 *
3875 * ARGUMENTS
3876 * SectionObjiect (OUT)
3877 * Caller supplied storage for the resulting pointer
3878 * to a SECTION_OBJECT instance;
3879 *
3880 * DesiredAccess
3881 * Specifies the desired access to the section can be a
3882 * combination of:
3883 * STANDARD_RIGHTS_REQUIRED |
3884 * SECTION_QUERY |
3885 * SECTION_MAP_WRITE |
3886 * SECTION_MAP_READ |
3887 * SECTION_MAP_EXECUTE
3888 *
3889 * ObjectAttributes [OPTIONAL]
3890 * Initialized attributes for the object can be used
3891 * to create a named section;
3892 *
3893 * MaximumSize
3894 * Maximizes the size of the memory section. Must be
3895 * non-NULL for a page-file backed section.
3896 * If value specified for a mapped file and the file is
3897 * not large enough, file will be extended.
3898 *
3899 * SectionPageProtection
3900 * Can be a combination of:
3901 * PAGE_READONLY |
3902 * PAGE_READWRITE |
3903 * PAGE_WRITEONLY |
3904 * PAGE_WRITECOPY
3905 *
3906 * AllocationAttributes
3907 * Can be a combination of:
3908 * SEC_IMAGE |
3909 * SEC_RESERVE
3910 *
3911 * FileHandle
3912 * Handle to a file to create a section mapped to a file
3913 * instead of a memory backed section;
3914 *
3915 * File
3916 * Unknown.
3917 *
3918 * RETURN VALUE
3919 * Status.
3920 *
3921 * @unimplemented
3922 */
3923 NTSTATUS STDCALL
3924 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
3925 IN ACCESS_MASK DesiredAccess,
3926 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3927 IN PLARGE_INTEGER MaximumSize,
3928 IN ULONG SectionPageProtection,
3929 IN ULONG AllocationAttributes,
3930 IN HANDLE FileHandle OPTIONAL,
3931 IN PFILE_OBJECT File OPTIONAL)
3932 {
3933 return (STATUS_NOT_IMPLEMENTED);
3934 }
3935
3936 /* EOF */