Fixed a memory leakage in MmCreateImageSection.
[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.80 2002/05/07 22:53:05 hbirr 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 #include <ddk/ntddk.h>
33 #include <internal/mm.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37 #include <internal/cc.h>
38 #include <ddk/ntifs.h>
39
40 #define NDEBUG
41 #include <internal/debug.h>
42
43 /* TYPES *********************************************************************/
44
45 typedef struct
46 {
47 PSECTION_OBJECT Section;
48 PMM_SECTION_SEGMENT Segment;
49 LARGE_INTEGER Offset;
50 BOOLEAN WasDirty;
51 BOOLEAN Private;
52 } MM_SECTION_PAGEOUT_CONTEXT;
53
54 /* GLOBALS *******************************************************************/
55
56 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
57
58 static GENERIC_MAPPING MmpSectionMapping = {
59 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
60 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
61 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
62 SECTION_ALL_ACCESS};
63
64 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
65 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
66
67 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
68 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
69 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
70 #define MAX_SHARE_COUNT 0x7FF
71 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
72 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
73 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
74
75 /* FUNCTIONS *****************************************************************/
76
77 VOID
78 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
79 {
80 ULONG i;
81
82 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
83 {
84 if (Segment->PageDirectory.PageTables[i] != NULL)
85 {
86 ExFreePool(Segment->PageDirectory.PageTables[i]);
87 }
88 }
89 }
90
91 VOID
92 MmFreeSectionSegments(PFILE_OBJECT FileObject)
93 {
94 if (FileObject->SectionObjectPointers->ImageSectionObject != NULL)
95 {
96 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
97
98 ULONG i;
99
100 ImageSectionObject =
101 (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointers->
102 ImageSectionObject;
103
104 for (i = 0; i < ImageSectionObject->NrSegments; i++)
105 {
106 if (ImageSectionObject->Segments[i].ReferenceCount != 0)
107 {
108 DPRINT1("Image segment %d still referenced (was %d)\n", i,
109 ImageSectionObject->Segments[i].ReferenceCount);
110 KeBugCheck(0);
111 }
112 MmFreePageTablesSectionSegment(&ImageSectionObject->Segments[i]);
113 }
114 ExFreePool(ImageSectionObject);
115 FileObject->SectionObjectPointers->ImageSectionObject = NULL;
116 }
117 if (FileObject->SectionObjectPointers->DataSectionObject != NULL)
118 {
119 PMM_SECTION_SEGMENT Segment;
120
121 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers->
122 DataSectionObject;
123
124 if (Segment->ReferenceCount != 0)
125 {
126 DPRINT1("Data segment still referenced\n");
127 KeBugCheck(0);
128 }
129 MmFreePageTablesSectionSegment(Segment);
130 ExFreePool(Segment);
131 FileObject->SectionObjectPointers->DataSectionObject = NULL;
132 }
133 }
134
135 NTSTATUS
136 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
137 PMEMORY_AREA MArea,
138 PVOID Address)
139 {
140 return(STATUS_UNSUCCESSFUL);
141 }
142
143 VOID
144 MmLockSection(PSECTION_OBJECT Section)
145 {
146 KeWaitForSingleObject(&Section->Lock,
147 UserRequest,
148 KernelMode,
149 FALSE,
150 NULL);
151 }
152
153 VOID
154 MmUnlockSection(PSECTION_OBJECT Section)
155 {
156 KeReleaseMutex(&Section->Lock, FALSE);
157 }
158
159 VOID
160 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
161 {
162 KeWaitForSingleObject(&Segment->Lock,
163 UserRequest,
164 KernelMode,
165 FALSE,
166 NULL);
167 }
168
169 VOID
170 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
171 {
172 KeReleaseMutex(&Segment->Lock, FALSE);
173 }
174
175 VOID
176 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
177 ULONG Offset,
178 ULONG Entry)
179 {
180 PSECTION_PAGE_TABLE Table;
181 ULONG DirectoryOffset;
182 ULONG TableOffset;
183
184 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
185 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
186 if (Table == NULL)
187 {
188 Table =
189 Segment->PageDirectory.PageTables[DirectoryOffset] =
190 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
191 TAG_SECTION_PAGE_TABLE);
192 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
193 DPRINT("Table %x\n", Table);
194 }
195 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
196 Table->Entry[TableOffset] = Entry;
197 }
198
199
200 ULONG
201 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
202 ULONG Offset)
203 {
204 PSECTION_PAGE_TABLE Table;
205 ULONG Entry;
206 ULONG DirectoryOffset;
207 ULONG TableOffset;
208
209 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
210
211 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
212 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
213 DPRINT("Table %x\n", Table);
214 if (Table == NULL)
215 {
216 return(0);
217 }
218 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
219 Entry = Table->Entry[TableOffset];
220 return(Entry);
221 }
222
223 VOID
224 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
225 ULONG Offset)
226 {
227 ULONG Entry;
228
229 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
230 if (Entry == 0)
231 {
232 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
233 KeBugCheck(0);
234 }
235 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
236 {
237 DPRINT1("Maximum share count reached\n");
238 KeBugCheck(0);
239 }
240 if (IS_SWAP_FROM_SSE(Entry))
241 {
242 KeBugCheck(0);
243 }
244 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
245 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
246 }
247
248 BOOLEAN
249 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
250 PMM_SECTION_SEGMENT Segment,
251 ULONG Offset,
252 BOOLEAN Dirty)
253 {
254 ULONG Entry;
255
256 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
257 if (Entry == 0)
258 {
259 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
260 KeBugCheck(0);
261 }
262 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
263 {
264 DPRINT1("Zero share count for unshare\n");
265 KeBugCheck(0);
266 }
267 if (IS_SWAP_FROM_SSE(Entry))
268 {
269 KeBugCheck(0);
270 }
271 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
272 /*
273 * If we reducing the share count of this entry to zero then set the entry
274 * to zero and tell the cache the page is no longer mapped.
275 */
276 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
277 {
278 PFILE_OBJECT FileObject;
279 PREACTOS_COMMON_FCB_HEADER Fcb;
280
281 MmSetPageEntrySectionSegment(Segment, Offset, 0);
282 FileObject = Section->FileObject;
283 if (FileObject != NULL)
284 {
285 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
286
287 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
288 (Offset % PAGESIZE) == 0)
289 {
290 NTSTATUS Status;
291 Status = CcRosUnmapCacheSegment(Fcb->Bcb, Offset, Dirty);
292 if (!NT_SUCCESS(Status))
293 {
294 KeBugCheck(0);
295 }
296 }
297 }
298 }
299 else
300 {
301 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
302 }
303 return(SHARE_COUNT_FROM_SSE(Entry) > 1);
304 }
305
306 NTSTATUS
307 MiReadPage(PMEMORY_AREA MemoryArea,
308 PLARGE_INTEGER Offset,
309 PVOID* Page)
310 /*
311 * FUNCTION: Read a page for a section backed memory area.
312 * PARAMETERS:
313 * MemoryArea - Memory area to read the page for.
314 * Offset - Offset of the page to read.
315 * Page - Variable that receives a page contains the read data.
316 */
317 {
318 IO_STATUS_BLOCK IoStatus;
319 PFILE_OBJECT FileObject;
320 PMDL Mdl;
321 NTSTATUS Status;
322 PREACTOS_COMMON_FCB_HEADER Fcb;
323
324 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
325 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
326
327 /*
328 * If the file system is letting us go directly to the cache and the
329 * memory area was mapped at an offset in the file which is page aligned
330 * then get the related cache segment.
331 */
332 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
333 (Offset->QuadPart % PAGESIZE) == 0)
334 {
335 ULONG BaseOffset;
336 PVOID BaseAddress;
337 BOOLEAN UptoDate;
338 PCACHE_SEGMENT CacheSeg;
339 LARGE_INTEGER SegOffset;
340 PHYSICAL_ADDRESS Addr;
341
342 /*
343 * Get the related cache segment; we use a lower level interface than
344 * filesystems do because it is safe for us to use an offset with a
345 * alignment less than the file system block size.
346 */
347 Status = CcRosGetCacheSegment(Fcb->Bcb,
348 (ULONG)Offset->QuadPart,
349 &BaseOffset,
350 &BaseAddress,
351 &UptoDate,
352 &CacheSeg);
353 if (!NT_SUCCESS(Status))
354 {
355 return(Status);
356 }
357 if (!UptoDate)
358 {
359 /*
360 * If the cache segment isn't up to date then call the file
361 * system to read in the data.
362 */
363
364 Mdl = MmCreateMdl(NULL, BaseAddress, Fcb->Bcb->CacheSegmentSize);
365 MmBuildMdlForNonPagedPool(Mdl);
366 SegOffset.QuadPart = BaseOffset;
367 Status = IoPageRead(FileObject,
368 Mdl,
369 &SegOffset,
370 &IoStatus,
371 TRUE);
372 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
373 {
374 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, FALSE, FALSE,
375 FALSE);
376 return(Status);
377 }
378 }
379 /*
380 * Retrieve the page from the cache segment that we actually want.
381 */
382 Addr = MmGetPhysicalAddress(BaseAddress +
383 Offset->QuadPart - BaseOffset);
384 (*Page) = (PVOID)(ULONG)Addr.QuadPart;
385 MmReferencePage((*Page));
386
387 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, TRUE);
388 return(STATUS_SUCCESS);
389 }
390 else
391 {
392 /*
393 * Allocate a page, this is rather complicated by the possibility
394 * we might have to move other things out of memory
395 */
396 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
397 if (!NT_SUCCESS(Status))
398 {
399 return(Status);
400 }
401
402 /*
403 * Create an mdl to hold the page we are going to read data into.
404 */
405 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
406 MmBuildMdlFromPages(Mdl, (PULONG)Page);
407 /*
408 * Call the FSD to read the page
409 */
410 Status = IoPageRead(FileObject,
411 Mdl,
412 Offset,
413 &IoStatus,
414 TRUE);
415 return(Status);
416 }
417 }
418
419 NTSTATUS
420 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
421 MEMORY_AREA* MemoryArea,
422 PVOID Address,
423 BOOLEAN Locked)
424 {
425 LARGE_INTEGER Offset;
426 PVOID Page;
427 NTSTATUS Status;
428 ULONG PAddress;
429 PSECTION_OBJECT Section;
430 PMM_SECTION_SEGMENT Segment;
431 ULONG Entry;
432 ULONG Entry1;
433 ULONG Attributes;
434 PMM_PAGEOP PageOp;
435
436 /*
437 * There is a window between taking the page fault and locking the
438 * address space when another thread could load the page so we check
439 * that.
440 */
441 if (MmIsPagePresent(NULL, Address))
442 {
443 if (Locked)
444 {
445 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
446 }
447 return(STATUS_SUCCESS);
448 }
449
450 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
451 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
452 MemoryArea->Data.SectionData.ViewOffset;
453
454 /*
455 * Lock the segment
456 */
457 Segment = MemoryArea->Data.SectionData.Segment;
458 Section = MemoryArea->Data.SectionData.Section;
459 MmLockSection(Section);
460 MmLockSectionSegment(Segment);
461
462 /*
463 * Get or create a page operation descriptor
464 */
465 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
466 MM_PAGEOP_PAGEIN);
467 if (PageOp == NULL)
468 {
469 DPRINT1("MmGetPageOp failed\n");
470 KeBugCheck(0);
471 }
472
473 /*
474 * Check if someone else is already handling this fault, if so wait
475 * for them
476 */
477 if (PageOp->Thread != PsGetCurrentThread())
478 {
479 MmUnlockSectionSegment(Segment);
480 MmUnlockSection(Section);
481 MmUnlockAddressSpace(AddressSpace);
482 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
483 0,
484 KernelMode,
485 FALSE,
486 NULL);
487 /*
488 * Check for various strange conditions
489 */
490 if (Status != STATUS_SUCCESS)
491 {
492 DPRINT1("Failed to wait for page op\n");
493 KeBugCheck(0);
494 }
495 if (PageOp->Status == STATUS_PENDING)
496 {
497 DPRINT1("Woke for page op before completion\n");
498 KeBugCheck(0);
499 }
500 /*
501 * If this wasn't a pagein then restart the operation
502 */
503 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
504 {
505 MmLockAddressSpace(AddressSpace);
506 MmReleasePageOp(PageOp);
507 DPRINT("Address 0x%.8X\n", Address);
508 return(STATUS_MM_RESTART_OPERATION);
509 }
510 /*
511 * If the thread handling this fault has failed then we don't retry
512 */
513 if (!NT_SUCCESS(PageOp->Status))
514 {
515 MmLockAddressSpace(AddressSpace);
516 DPRINT("Address 0x%.8X\n", Address);
517 return(PageOp->Status);
518 }
519 MmLockAddressSpace(AddressSpace);
520 MmLockSection(Section);
521 MmLockSectionSegment(Segment);
522 /*
523 * If the completed fault was for another address space then set the
524 * page in this one.
525 */
526 if (!MmIsPagePresent(NULL, Address))
527 {
528 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
529 if (Entry == 0)
530 {
531 MmUnlockSectionSegment(Segment);
532 MmUnlockSection(Section);
533 MmReleasePageOp(PageOp);
534 return(STATUS_MM_RESTART_OPERATION);
535 }
536
537 Page = (PVOID)(PAGE_FROM_SSE(Entry));
538 MmReferencePage(Page);
539 MmSharePageEntrySectionSegment(Segment, Offset.u.LowPart);
540
541 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
542 Address,
543 Attributes,
544 (ULONG)Page,
545 FALSE);
546 if (!NT_SUCCESS(Status))
547 {
548 DbgPrint("Unable to create virtual mapping\n");
549 KeBugCheck(0);
550 }
551 MmInsertRmap(Page, PsGetCurrentProcess(),
552 (PVOID)PAGE_ROUND_DOWN(Address));
553 }
554 if (Locked)
555 {
556 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
557 }
558 MmUnlockSectionSegment(Segment);
559 MmUnlockSection(Section);
560 MmReleasePageOp(PageOp);
561 DPRINT("Address 0x%.8X\n", Address);
562 return(STATUS_SUCCESS);
563 }
564
565 /*
566 * Must be private page we have swapped out.
567 */
568 if (MmIsPageSwapEntry(NULL, (PVOID)PAddress))
569 {
570 SWAPENTRY SwapEntry;
571 PMDL Mdl;
572
573 MmUnlockSectionSegment(Segment);
574 MmUnlockSection(Section);
575
576 MmDeletePageFileMapping(NULL, (PVOID)PAddress, &SwapEntry);
577
578 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
579 if (!NT_SUCCESS(Status))
580 {
581 KeBugCheck(0);
582 }
583
584 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
585 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
586 Status = MmReadFromSwapPage(SwapEntry, Mdl);
587 if (!NT_SUCCESS(Status))
588 {
589 KeBugCheck(0);
590 }
591
592 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
593 Address,
594 MemoryArea->Attributes,
595 (ULONG)Page,
596 FALSE);
597 while (Status == STATUS_NO_MEMORY)
598 {
599 MmUnlockAddressSpace(AddressSpace);
600 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
601 Address,
602 MemoryArea->Attributes,
603 (ULONG)Page,
604 TRUE);
605 MmLockAddressSpace(AddressSpace);
606 }
607 if (!NT_SUCCESS(Status))
608 {
609 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
610 KeBugCheck(0);
611 return(Status);
612 }
613
614 /*
615 * Store the swap entry for later use.
616 */
617 MmSetSavedSwapEntryPage(Page, SwapEntry);
618
619 /*
620 * Add the page to the process's working set
621 */
622 MmInsertRmap(Page, PsGetCurrentProcess(),
623 (PVOID)PAGE_ROUND_DOWN(Address));
624
625 /*
626 * Finish the operation
627 */
628 if (Locked)
629 {
630 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
631 }
632 PageOp->Status = STATUS_SUCCESS;
633 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
634 MmReleasePageOp(PageOp);
635 DPRINT("Address 0x%.8X\n", Address);
636 return(STATUS_SUCCESS);
637 }
638
639 /*
640 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
641 */
642 if (Section->Flags & SO_PHYSICAL_MEMORY)
643 {
644 /*
645 * Just map the desired physical page
646 */
647 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
648 Address,
649 MemoryArea->Attributes,
650 Offset.QuadPart,
651 FALSE);
652 /*
653 * Don't add an rmap entry since the page mapped could be for
654 * anything.
655 */
656 if (Locked)
657 {
658 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
659 }
660
661 /*
662 * Cleanup and release locks
663 */
664 PageOp->Status = STATUS_SUCCESS;
665 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
666 MmReleasePageOp(PageOp);
667 MmUnlockSectionSegment(Segment);
668 MmUnlockSection(Section);
669 DPRINT("Address 0x%.8X\n", Address);
670 return(STATUS_SUCCESS);
671 }
672
673 /*
674 * Map anonymous memory for BSS sections
675 */
676 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
677 {
678 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
679 if (!NT_SUCCESS(Status))
680 {
681 MmUnlockSectionSegment(Segment);
682 MmUnlockSection(Section);
683 MmUnlockAddressSpace(AddressSpace);
684 MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
685 MmLockAddressSpace(AddressSpace);
686 MmLockSection(Section);
687 MmLockSectionSegment(Segment);
688 }
689
690 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
691 Address,
692 MemoryArea->Attributes,
693 (ULONG)Page,
694 FALSE);
695 MmInsertRmap(Page, PsGetCurrentProcess(),
696 (PVOID)PAGE_ROUND_DOWN(Address));
697 if (Locked)
698 {
699 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
700 }
701
702 /*
703 * Cleanup and release locks
704 */
705 PageOp->Status = STATUS_SUCCESS;
706 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
707 MmReleasePageOp(PageOp);
708 MmUnlockSectionSegment(Segment);
709 MmUnlockSection(Section);
710 DPRINT("Address 0x%.8X\n", Address);
711 return(STATUS_SUCCESS);
712 }
713
714 /*
715 * Check if this page needs to be mapped COW
716 */
717 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
718 (MemoryArea->Attributes == PAGE_READWRITE ||
719 MemoryArea->Attributes == PAGE_EXECUTE_READWRITE))
720 {
721 Attributes = PAGE_READONLY;
722 }
723 else
724 {
725 Attributes = MemoryArea->Attributes;
726 }
727
728 /*
729 * Get the entry corresponding to the offset within the section
730 */
731 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
732
733 if (Entry == 0)
734 {
735 /*
736 * If the entry is zero (and it can't change because we have
737 * locked the segment) then we need to load the page.
738 */
739
740 /*
741 * Release all our locks and read in the page from disk
742 */
743 MmUnlockSectionSegment(Segment);
744 MmUnlockSection(Section);
745 MmUnlockAddressSpace(AddressSpace);
746
747 if (Segment->Flags & MM_PAGEFILE_SECTION)
748 {
749 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
750 }
751 else
752 {
753 Status = MiReadPage(MemoryArea, &Offset, &Page);
754 }
755 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
756 {
757 /*
758 * FIXME: What do we know in this case?
759 */
760 DPRINT1("IoPageRead failed (Status %x)\n", Status);
761
762 /*
763 * Cleanup and release locks
764 */
765 PageOp->Status = Status;
766 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
767 MmReleasePageOp(PageOp);
768 MmLockAddressSpace(AddressSpace);
769 return(Status);
770 }
771
772 /*
773 * Relock the address space, section and segment
774 */
775 MmLockAddressSpace(AddressSpace);
776 MmLockSection(Section);
777 MmLockSectionSegment(Segment);
778
779 /*
780 * Check the entry. No one should change the status of a page
781 * that has a pending page-in.
782 */
783 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
784 if (Entry != Entry1)
785 {
786 DbgPrint("Someone changed ppte entry while we slept\n");
787 KeBugCheck(0);
788 }
789
790 /*
791 * Mark the offset within the section as having valid, in-memory
792 * data
793 */
794 Entry = (ULONG)Page;
795 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
796 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
797
798 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
799 Address,
800 Attributes,
801 (ULONG)Page,
802 FALSE);
803 if (!NT_SUCCESS(Status))
804 {
805 MmUnlockSectionSegment(Segment);
806 MmUnlockSection(Section);
807 MmUnlockAddressSpace(AddressSpace);
808 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
809 Address,
810 Attributes,
811 (ULONG)Page,
812 TRUE);
813 if (!NT_SUCCESS(Status))
814 {
815 KeBugCheck(0);
816 }
817 MmLockAddressSpace(AddressSpace);
818 MmLockSection(Section);
819 MmLockSectionSegment(Segment);
820 }
821 MmInsertRmap(Page, PsGetCurrentProcess(),
822 (PVOID)PAGE_ROUND_DOWN(Address));
823 if (!NT_SUCCESS(Status))
824 {
825 DbgPrint("Unable to create virtual mapping\n");
826 KeBugCheck(0);
827 }
828 if (Locked)
829 {
830 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
831 }
832 PageOp->Status = STATUS_SUCCESS;
833 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
834 MmReleasePageOp(PageOp);
835 MmUnlockSectionSegment(Segment);
836 MmUnlockSection(Section);
837 DPRINT("MmNotPresentFaultSectionView succeeded\n");
838 return(STATUS_SUCCESS);
839 }
840 else if (IS_SWAP_FROM_SSE(Entry))
841 {
842 SWAPENTRY SwapEntry;
843 PMDL Mdl;
844
845 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
846
847 /*
848 * Release all our locks and read in the page from disk
849 */
850 MmUnlockSectionSegment(Segment);
851 MmUnlockSection(Section);
852 MmUnlockAddressSpace(AddressSpace);
853
854 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
855 if (!NT_SUCCESS(Status))
856 {
857 KeBugCheck(0);
858 }
859
860 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
861 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
862 Status = MmReadFromSwapPage(SwapEntry, Mdl);
863 if (!NT_SUCCESS(Status))
864 {
865 KeBugCheck(0);
866 }
867
868 /*
869 * Relock the address space, section and segment
870 */
871 MmLockAddressSpace(AddressSpace);
872 MmLockSection(Section);
873 MmLockSectionSegment(Segment);
874
875 /*
876 * Check the entry. No one should change the status of a page
877 * that has a pending page-in.
878 */
879 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
880 if (Entry != Entry1)
881 {
882 DbgPrint("Someone changed ppte entry while we slept\n");
883 KeBugCheck(0);
884 }
885
886 /*
887 * Mark the offset within the section as having valid, in-memory
888 * data
889 */
890 Entry = (ULONG)Page;
891 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
892 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
893
894 /*
895 * Save the swap entry.
896 */
897 MmSetSavedSwapEntryPage(Page, SwapEntry);
898
899 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
900 Address,
901 Attributes,
902 (ULONG)Page,
903 FALSE);
904 MmInsertRmap(Page, PsGetCurrentProcess(),
905 (PVOID)PAGE_ROUND_DOWN(Address));
906 if (!NT_SUCCESS(Status))
907 {
908 DbgPrint("Unable to create virtual mapping\n");
909 KeBugCheck(0);
910 }
911 if (Locked)
912 {
913 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
914 }
915 PageOp->Status = STATUS_SUCCESS;
916 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
917 MmReleasePageOp(PageOp);
918 MmUnlockSectionSegment(Segment);
919 MmUnlockSection(Section);
920 DPRINT("MmNotPresentFaultSectionView succeeded\n");
921 return(STATUS_SUCCESS);
922 }
923 else
924 {
925 /*
926 * If the section offset is already in-memory and valid then just
927 * take another reference to the page
928 */
929
930 Page = (PVOID)PAGE_FROM_SSE(Entry);
931 MmReferencePage(Page);
932 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
933
934 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
935 Address,
936 Attributes,
937 (ULONG)Page,
938 FALSE);
939 MmInsertRmap(Page, PsGetCurrentProcess(),
940 (PVOID)PAGE_ROUND_DOWN(Address));
941 if (!NT_SUCCESS(Status))
942 {
943 DbgPrint("Unable to create virtual mapping\n");
944 KeBugCheck(0);
945 }
946 if (Locked)
947 {
948 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
949 }
950 PageOp->Status = STATUS_SUCCESS;
951 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
952 MmReleasePageOp(PageOp);
953 MmUnlockSectionSegment(Segment);
954 MmUnlockSection(Section);
955 return(STATUS_SUCCESS);
956 }
957 }
958
959 NTSTATUS
960 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
961 MEMORY_AREA* MemoryArea,
962 PVOID Address,
963 BOOLEAN Locked)
964 {
965 PMM_SECTION_SEGMENT Segment;
966 PSECTION_OBJECT Section;
967 ULONG OldPage;
968 PVOID NewPage;
969 PVOID NewAddress;
970 NTSTATUS Status;
971 ULONG PAddress;
972 LARGE_INTEGER Offset;
973 PMM_PAGEOP PageOp;
974
975 /*
976 * Check if the page has been paged out or has already been set readwrite
977 */
978 if (!MmIsPagePresent(NULL, Address) ||
979 MmGetPageProtect(NULL, Address) & PAGE_READWRITE)
980 {
981 return(STATUS_SUCCESS);
982 }
983
984 /*
985 * Find the offset of the page
986 */
987 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
988 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
989 MemoryArea->Data.SectionData.ViewOffset;
990
991 /*
992 * Lock the segment
993 */
994 Segment = MemoryArea->Data.SectionData.Segment;
995 Section = MemoryArea->Data.SectionData.Section;
996 MmLockSection(Section);
997 MmLockSectionSegment(Segment);
998
999 /*
1000 * Sanity check.
1001 */
1002 if (MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) == 0)
1003 {
1004 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1005 Address);
1006 }
1007
1008 /*
1009 * Check if we are doing COW
1010 */
1011 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1012 (MemoryArea->Attributes == PAGE_READWRITE ||
1013 MemoryArea->Attributes == PAGE_EXECUTE_READWRITE)))
1014 {
1015 MmUnlockSection(Section);
1016 MmUnlockSectionSegment(Segment);
1017 return(STATUS_UNSUCCESSFUL);
1018 }
1019
1020 /*
1021 * Get or create a pageop
1022 */
1023 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
1024 MM_PAGEOP_ACCESSFAULT);
1025 if (PageOp == NULL)
1026 {
1027 DPRINT1("MmGetPageOp failed\n");
1028 KeBugCheck(0);
1029 }
1030
1031 /*
1032 * Wait for any other operations to complete
1033 */
1034 if (PageOp->Thread != PsGetCurrentThread())
1035 {
1036 MmUnlockSectionSegment(Segment);
1037 MmUnlockSection(Section);
1038 MmUnlockAddressSpace(AddressSpace);
1039 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1040 0,
1041 KernelMode,
1042 FALSE,
1043 NULL);
1044 /*
1045 * Check for various strange conditions
1046 */
1047 if (Status != STATUS_SUCCESS)
1048 {
1049 DPRINT1("Failed to wait for page op\n");
1050 KeBugCheck(0);
1051 }
1052 if (PageOp->Status == STATUS_PENDING)
1053 {
1054 DPRINT1("Woke for page op before completion\n");
1055 KeBugCheck(0);
1056 }
1057 /*
1058 * Restart the operation
1059 */
1060 MmLockAddressSpace(AddressSpace);
1061 MmReleasePageOp(PageOp);
1062 return(STATUS_MM_RESTART_OPERATION);
1063 }
1064
1065 /*
1066 * Release locks now we have the pageop
1067 */
1068 MmUnlockSectionSegment(Segment);
1069 MmUnlockSection(Section);
1070 MmUnlockAddressSpace(AddressSpace);
1071
1072 /*
1073 * Allocate a page
1074 */
1075 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1076
1077 /*
1078 * Copy the old page
1079 */
1080 OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1081
1082 NewAddress = ExAllocatePageWithPhysPage((ULONG)NewPage);
1083 memcpy(NewAddress, (PVOID)PAGE_ROUND_DOWN(Address), PAGESIZE);
1084 ExUnmapPage(NewAddress);
1085
1086 /*
1087 * Delete the old entry.
1088 */
1089 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE, NULL, NULL);
1090
1091 /*
1092 * Set the PTE to point to the new page
1093 */
1094 MmLockAddressSpace(AddressSpace);
1095 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
1096 Address,
1097 MemoryArea->Attributes,
1098 (ULONG)NewPage,
1099 FALSE);
1100 MmInsertRmap(NewPage, PsGetCurrentProcess(),
1101 (PVOID)PAGE_ROUND_DOWN(Address));
1102 if (!NT_SUCCESS(Status))
1103 {
1104 DbgPrint("Unable to create virtual mapping\n");
1105 KeBugCheck(0);
1106 }
1107 if (Locked)
1108 {
1109 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
1110 }
1111
1112 /*
1113 * Unshare the old page.
1114 */
1115 MmUnsharePageEntrySectionSegment(Section, Segment, Offset.QuadPart, FALSE);
1116 MmDeleteRmap((PVOID)OldPage, PsGetCurrentProcess(),
1117 (PVOID)PAGE_ROUND_DOWN(Address));
1118 MmDereferencePage((PVOID)OldPage);
1119
1120 PageOp->Status = STATUS_SUCCESS;
1121 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1122 MmReleasePageOp(PageOp);
1123 return(STATUS_SUCCESS);
1124 }
1125
1126 VOID
1127 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1128 {
1129 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1130 BOOL WasDirty;
1131 PVOID PhysicalAddress;
1132
1133 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1134 MmDeleteVirtualMapping(Process,
1135 Address,
1136 FALSE,
1137 &WasDirty,
1138 (PULONG)&PhysicalAddress);
1139 if (WasDirty)
1140 {
1141 PageOutContext->WasDirty = TRUE;
1142 }
1143 if (!PageOutContext->Private)
1144 {
1145 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1146 PageOutContext->Segment,
1147 PageOutContext->Offset.u.LowPart,
1148 PageOutContext->WasDirty);
1149 }
1150 MmDereferencePage(PhysicalAddress);
1151 }
1152
1153 NTSTATUS
1154 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1155 MEMORY_AREA* MemoryArea,
1156 PVOID Address,
1157 PMM_PAGEOP PageOp)
1158 {
1159 LARGE_INTEGER Offset;
1160 PSECTION_OBJECT Section;
1161 PMM_SECTION_SEGMENT Segment;
1162 PVOID PhysicalAddress;
1163 MM_SECTION_PAGEOUT_CONTEXT Context;
1164 SWAPENTRY SwapEntry;
1165 PMDL Mdl;
1166 ULONG Entry;
1167 BOOLEAN Private;
1168 NTSTATUS Status;
1169 PFILE_OBJECT FileObject;
1170 PREACTOS_COMMON_FCB_HEADER Fcb;
1171 BOOLEAN DirectMapped;
1172
1173 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1174
1175 Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1176 MemoryArea->Data.SectionData.ViewOffset;
1177
1178 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1179 DirectMapped = FALSE;
1180 if (FileObject != NULL)
1181 {
1182 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
1183
1184 /*
1185 * If the file system is letting us go directly to the cache and the
1186 * memory area was mapped at an offset in the file which is page aligned
1187 * then note this is a direct mapped page.
1188 */
1189 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1190 (Offset.QuadPart % PAGESIZE) == 0)
1191 {
1192 DirectMapped = TRUE;
1193 }
1194 }
1195
1196 /*
1197 * Get the segment and section.
1198 */
1199 Segment = MemoryArea->Data.SectionData.Segment;
1200 Section = MemoryArea->Data.SectionData.Section;
1201
1202 /*
1203 * This should never happen since mappings of physical memory are never
1204 * placed in the rmap lists.
1205 */
1206 if (Section->Flags & SO_PHYSICAL_MEMORY)
1207 {
1208 DPRINT1("Trying to page out from physical memory section address 0x%X "
1209 "process %d\n", Address, AddressSpace->Process->UniqueProcessId);
1210 KeBugCheck(0);
1211 }
1212
1213 /*
1214 * Get the section segment entry and the physical address.
1215 */
1216 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1217 if (!MmIsPagePresent(AddressSpace->Process, Address))
1218 {
1219 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1220 AddressSpace->Process->UniqueProcessId, Address);
1221 KeBugCheck(0);
1222 }
1223 PhysicalAddress =
1224 (PVOID)MmGetPhysicalAddressForProcess(AddressSpace->Process,
1225 Address);
1226 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1227
1228 /*
1229 * Prepare the context structure for the rmap delete call.
1230 */
1231 Context.Section = Section;
1232 Context.Segment = Segment;
1233 Context.Offset = Offset;
1234 Context.WasDirty = FALSE;
1235 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1236 IS_SWAP_FROM_SSE(Entry) ||
1237 (PVOID)(PAGE_FROM_SSE(Entry)) != PhysicalAddress)
1238 {
1239 Context.Private = Private = TRUE;
1240 }
1241 else
1242 {
1243 Context.Private = Private = FALSE;
1244 }
1245
1246 /*
1247 * Take an additional reference to the page.
1248 */
1249 MmReferencePage(PhysicalAddress);
1250
1251 /*
1252 * Paging out data mapped read-only is easy.
1253 */
1254 if (MemoryArea->Attributes & PAGE_READONLY ||
1255 MemoryArea->Attributes & PAGE_EXECUTE_READ)
1256 {
1257 /*
1258 * Read-only data should never be in the swapfile.
1259 */
1260 if (SwapEntry != 0)
1261 {
1262 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1263 "paddress 0x%.8X\n", SwapEntry, Address,
1264 PhysicalAddress);
1265 KeBugCheck(0);
1266 }
1267
1268 /*
1269 * Read-only data should never be COWed
1270 */
1271 if (Private)
1272 {
1273 DPRINT1("Had private copy of read-only page.\n");
1274 KeBugCheck(0);
1275 }
1276
1277 /*
1278 * Delete all mappings of this page.
1279 */
1280 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context,
1281 MmPageOutDeleteMapping);
1282 if (Context.WasDirty)
1283 {
1284 KeBugCheck(0);
1285 }
1286 /*
1287 * If this page wasn't direct mapped then we have a private copy so
1288 * release back to the system; otherwise the cache manager will have
1289 * handled freeing the cache segment which we mapped from.
1290 */
1291 if (!DirectMapped)
1292 {
1293 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1294 }
1295
1296 PageOp->Status = STATUS_SUCCESS;
1297 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1298 MmReleasePageOp(PageOp);
1299 return(STATUS_SUCCESS);
1300 }
1301
1302 /*
1303 * Otherwise we have read-write data.
1304 */
1305 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1306
1307 /*
1308 * If this wasn't a private page then we should have reduced the entry to
1309 * zero by deleting all the rmaps.
1310 */
1311 if (!Private && MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) != 0)
1312 {
1313 KeBugCheck(0);
1314 }
1315
1316 /*
1317 * If the page wasn't dirty then we can just free it as for a readonly page.
1318 * Since we unmapped all the mappings above we know it will not suddenly
1319 * become dirty.
1320 */
1321 if (!Context.WasDirty)
1322 {
1323 if (!DirectMapped || Private)
1324 {
1325 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1326 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1327 }
1328 if (Private)
1329 {
1330 if (!(Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1331 SwapEntry == 0)
1332 {
1333 DPRINT1("Private page, non-dirty but not swapped out "
1334 "process %d address 0x%.8X\n",
1335 AddressSpace->Process->UniqueProcessId,
1336 Address);
1337 KeBugCheck(0);
1338 }
1339 else
1340 {
1341 Status = MmCreatePageFileMapping(AddressSpace->Process,
1342 Address,
1343 SwapEntry);
1344 if (!NT_SUCCESS(Status))
1345 {
1346 KeBugCheck(0);
1347 }
1348 }
1349 }
1350
1351 PageOp->Status = STATUS_SUCCESS;
1352 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1353 MmReleasePageOp(PageOp);
1354 return(STATUS_SUCCESS);
1355 }
1356
1357 /*
1358 * If this page was direct mapped from the cache then the cache manager
1359 * will already have taken care of writing it back.
1360 */
1361 if (DirectMapped && !Private)
1362 {
1363 assert(SwapEntry == 0);
1364 MmDereferencePage((PVOID)PhysicalAddress);
1365 PageOp->Status = STATUS_SUCCESS;
1366 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1367 MmReleasePageOp(PageOp);
1368 return(STATUS_SUCCESS);
1369 }
1370
1371 /*
1372 * If necessary, allocate an entry in the paging file for this page
1373 */
1374 SwapEntry = MmGetSavedSwapEntryPage((PVOID)PhysicalAddress);
1375 if (SwapEntry == 0)
1376 {
1377 SwapEntry = MmAllocSwapPage();
1378 if (SwapEntry == 0)
1379 {
1380 /*
1381 * For private pages restore the old mappings.
1382 */
1383 if (Private)
1384 {
1385 Status = MmCreateVirtualMapping(MemoryArea->Process,
1386 Address,
1387 MemoryArea->Attributes,
1388 (ULONG)PhysicalAddress,
1389 FALSE);
1390 MmSetDirtyPage(MemoryArea->Process, Address);
1391 MmInsertRmap(PhysicalAddress,
1392 MemoryArea->Process,
1393 Address);
1394 }
1395 else
1396 {
1397 /*
1398 * For non-private pages if the page wasn't direct mapped then
1399 * set it back into the section segment entry so we don't loose
1400 * our copy. Otherwise it will be handled by the cache manager.
1401 */
1402 Status = MmCreateVirtualMapping(MemoryArea->Process,
1403 Address,
1404 MemoryArea->Attributes,
1405 (ULONG)PhysicalAddress,
1406 FALSE);
1407 MmSetDirtyPage(MemoryArea->Process, Address);
1408 MmInsertRmap(PhysicalAddress,
1409 MemoryArea->Process,
1410 Address);
1411 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1412 (ULONG)PhysicalAddress);
1413 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1414 }
1415 PageOp->Status = STATUS_UNSUCCESSFUL;
1416 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1417 MmReleasePageOp(PageOp);
1418 return(STATUS_UNSUCCESSFUL);
1419 }
1420 }
1421
1422 /*
1423 * Write the page to the pagefile
1424 */
1425 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
1426 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1427 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1428 if (!NT_SUCCESS(Status))
1429 {
1430 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1431 Status);
1432 /*
1433 * As above: undo our actions.
1434 * FIXME: Also free the swap page.
1435 */
1436 if (Private)
1437 {
1438 Status = MmCreateVirtualMapping(MemoryArea->Process,
1439 Address,
1440 MemoryArea->Attributes,
1441 (ULONG)PhysicalAddress,
1442 FALSE);
1443 MmSetDirtyPage(MemoryArea->Process, Address);
1444 MmInsertRmap(PhysicalAddress,
1445 MemoryArea->Process,
1446 Address);
1447 }
1448 else
1449 {
1450 Status = MmCreateVirtualMapping(MemoryArea->Process,
1451 Address,
1452 MemoryArea->Attributes,
1453 (ULONG)PhysicalAddress,
1454 FALSE);
1455 MmSetDirtyPage(MemoryArea->Process, Address);
1456 MmInsertRmap(PhysicalAddress,
1457 MemoryArea->Process,
1458 Address);
1459 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1460 (ULONG)PhysicalAddress);
1461 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1462 }
1463 PageOp->Status = STATUS_UNSUCCESSFUL;
1464 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1465 MmReleasePageOp(PageOp);
1466 return(STATUS_UNSUCCESSFUL);
1467 }
1468
1469 /*
1470 * Otherwise we have succeeded.
1471 */
1472 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1473 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1474 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1475
1476 if (Private)
1477 {
1478 Status = MmCreatePageFileMapping(MemoryArea->Process,
1479 Address,
1480 SwapEntry);
1481 if (!NT_SUCCESS(Status))
1482 {
1483 KeBugCheck(0);
1484 }
1485 }
1486 else
1487 {
1488 Entry = MAKE_SWAP_SSE(SwapEntry);
1489 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
1490 }
1491
1492 PageOp->Status = STATUS_SUCCESS;
1493 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1494 MmReleasePageOp(PageOp);
1495 return(STATUS_SUCCESS);
1496 }
1497
1498 VOID STDCALL
1499 MmpDeleteSection(PVOID ObjectBody)
1500 {
1501 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
1502
1503 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
1504 if (Section->Flags & MM_IMAGE_SECTION)
1505 {
1506 ULONG i;
1507
1508 for (i = 0; i < Section->NrSegments; i++)
1509 {
1510 InterlockedDecrement(&Section->Segments[i].ReferenceCount);
1511 }
1512 }
1513 else
1514 {
1515 InterlockedDecrement(&Section->Segments->ReferenceCount);
1516 }
1517 if (Section->FileObject != NULL)
1518 {
1519 ObDereferenceObject(Section->FileObject);
1520 Section->FileObject = NULL;
1521 }
1522 }
1523
1524 VOID STDCALL
1525 MmpCloseSection(PVOID ObjectBody,
1526 ULONG HandleCount)
1527 {
1528 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1529 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
1530
1531 }
1532
1533 NTSTATUS STDCALL
1534 MmpCreateSection(PVOID ObjectBody,
1535 PVOID Parent,
1536 PWSTR RemainingPath,
1537 POBJECT_ATTRIBUTES ObjectAttributes)
1538 {
1539 DPRINT("MmpCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
1540 ObjectBody, Parent, RemainingPath);
1541
1542 if (RemainingPath == NULL)
1543 {
1544 return(STATUS_SUCCESS);
1545 }
1546
1547 if (wcschr(RemainingPath+1, L'\\') != NULL)
1548 {
1549 return(STATUS_UNSUCCESSFUL);
1550 }
1551
1552 return(STATUS_SUCCESS);
1553 }
1554
1555 NTSTATUS
1556 MmCreatePhysicalMemorySection(VOID)
1557 {
1558 HANDLE PhysSectionH;
1559 PSECTION_OBJECT PhysSection;
1560 NTSTATUS Status;
1561 OBJECT_ATTRIBUTES Obj;
1562 UNICODE_STRING Name;
1563 LARGE_INTEGER SectionSize;
1564
1565 /*
1566 * Create the section mapping physical memory
1567 */
1568 SectionSize.QuadPart = 0xFFFFFFFF;
1569 RtlInitUnicodeString(&Name, L"\\Device\\PhysicalMemory");
1570 InitializeObjectAttributes(&Obj,
1571 &Name,
1572 0,
1573 NULL,
1574 NULL);
1575 Status = NtCreateSection(&PhysSectionH,
1576 SECTION_ALL_ACCESS,
1577 &Obj,
1578 &SectionSize,
1579 PAGE_EXECUTE_READWRITE,
1580 0,
1581 NULL);
1582 if (!NT_SUCCESS(Status))
1583 {
1584 DbgPrint("Failed to create PhysicalMemory section\n");
1585 KeBugCheck(0);
1586 }
1587 Status = ObReferenceObjectByHandle(PhysSectionH,
1588 SECTION_ALL_ACCESS,
1589 NULL,
1590 KernelMode,
1591 (PVOID*)&PhysSection,
1592 NULL);
1593 if (!NT_SUCCESS(Status))
1594 {
1595 DbgPrint("Failed to reference PhysicalMemory section\n");
1596 KeBugCheck(0);
1597 }
1598 PhysSection->Flags = PhysSection->Flags | SO_PHYSICAL_MEMORY;
1599 ObDereferenceObject((PVOID)PhysSection);
1600
1601 return(STATUS_SUCCESS);
1602 }
1603
1604 NTSTATUS
1605 MmInitSectionImplementation(VOID)
1606 {
1607 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
1608
1609 RtlInitUnicodeString(&MmSectionObjectType->TypeName, L"Section");
1610
1611 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
1612 MmSectionObjectType->TotalObjects = 0;
1613 MmSectionObjectType->TotalHandles = 0;
1614 MmSectionObjectType->MaxObjects = ULONG_MAX;
1615 MmSectionObjectType->MaxHandles = ULONG_MAX;
1616 MmSectionObjectType->PagedPoolCharge = 0;
1617 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
1618 MmSectionObjectType->Mapping = &MmpSectionMapping;
1619 MmSectionObjectType->Dump = NULL;
1620 MmSectionObjectType->Open = NULL;
1621 MmSectionObjectType->Close = MmpCloseSection;
1622 MmSectionObjectType->Delete = MmpDeleteSection;
1623 MmSectionObjectType->Parse = NULL;
1624 MmSectionObjectType->Security = NULL;
1625 MmSectionObjectType->QueryName = NULL;
1626 MmSectionObjectType->OkayToClose = NULL;
1627 MmSectionObjectType->Create = MmpCreateSection;
1628 MmSectionObjectType->DuplicationNotify = NULL;
1629
1630 return(STATUS_SUCCESS);
1631 }
1632
1633 NTSTATUS
1634 MmCreatePageFileSection(PHANDLE SectionHandle,
1635 ACCESS_MASK DesiredAccess,
1636 POBJECT_ATTRIBUTES ObjectAttributes,
1637 PLARGE_INTEGER UMaximumSize,
1638 ULONG SectionPageProtection,
1639 ULONG AllocationAttributes)
1640 /*
1641 * Create a section which is backed by the pagefile
1642 */
1643 {
1644 LARGE_INTEGER MaximumSize;
1645 PSECTION_OBJECT Section;
1646 PMM_SECTION_SEGMENT Segment;
1647 NTSTATUS Status;
1648
1649 if (UMaximumSize == NULL)
1650 {
1651 return(STATUS_UNSUCCESSFUL);
1652 }
1653 MaximumSize = *UMaximumSize;
1654
1655 /*
1656 * Check the protection
1657 */
1658 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
1659 SectionPageProtection)
1660 {
1661 return(STATUS_INVALID_PAGE_PROTECTION);
1662 }
1663
1664 /*
1665 * Create the section
1666 */
1667 Status = ObCreateObject(SectionHandle,
1668 DesiredAccess,
1669 ObjectAttributes,
1670 MmSectionObjectType,
1671 (PVOID*)&Section);
1672 if (!NT_SUCCESS(Status))
1673 {
1674 return(Status);
1675 }
1676
1677 /*
1678 * Initialize it
1679 */
1680 Section->SectionPageProtection = SectionPageProtection;
1681 Section->AllocateAttributes = AllocationAttributes;
1682 InitializeListHead(&Section->ViewListHead);
1683 KeInitializeSpinLock(&Section->ViewListLock);
1684 KeInitializeMutex(&Section->Lock, 0);
1685 Section->Flags = 0;
1686 Section->FileObject = NULL;
1687 Section->MaximumSize = MaximumSize;
1688 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
1689 TAG_MM_SECTION_SEGMENT);
1690 if (Segment == NULL)
1691 {
1692 ZwClose(*SectionHandle);
1693 ObDereferenceObject(Section);
1694 return(STATUS_NO_MEMORY);
1695 }
1696 Section->Segments = Segment;
1697 Segment->ReferenceCount = 1;
1698 KeInitializeMutex(&Segment->Lock, 0);
1699 Segment->FileOffset = 0;
1700 Segment->Protection = SectionPageProtection;
1701 Segment->Attributes = AllocationAttributes;
1702 Segment->Length = MaximumSize.u.LowPart;
1703 Segment->Flags = MM_PAGEFILE_SECTION;
1704 Segment->WriteCopy = FALSE;
1705 return(STATUS_SUCCESS);
1706 }
1707
1708
1709 NTSTATUS
1710 MmCreateDataFileSection(PHANDLE SectionHandle,
1711 ACCESS_MASK DesiredAccess,
1712 POBJECT_ATTRIBUTES ObjectAttributes,
1713 PLARGE_INTEGER UMaximumSize,
1714 ULONG SectionPageProtection,
1715 ULONG AllocationAttributes,
1716 HANDLE FileHandle)
1717 /*
1718 * Create a section backed by a data file
1719 */
1720 {
1721 PSECTION_OBJECT Section;
1722 NTSTATUS Status;
1723 LARGE_INTEGER MaximumSize;
1724 PFILE_OBJECT FileObject;
1725 PMM_SECTION_SEGMENT Segment;
1726 ULONG FileAccess;
1727
1728 /*
1729 * Check the protection
1730 */
1731 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
1732 SectionPageProtection)
1733 {
1734 return(STATUS_INVALID_PAGE_PROTECTION);
1735 }
1736
1737 /*
1738 * Create the section
1739 */
1740 Status = ObCreateObject(SectionHandle,
1741 DesiredAccess,
1742 ObjectAttributes,
1743 MmSectionObjectType,
1744 (PVOID*)&Section);
1745 if (!NT_SUCCESS(Status))
1746 {
1747 return(Status);
1748 }
1749
1750 /*
1751 * Initialize it
1752 */
1753 Section->SectionPageProtection = SectionPageProtection;
1754 Section->AllocateAttributes = AllocationAttributes;
1755 InitializeListHead(&Section->ViewListHead);
1756 KeInitializeSpinLock(&Section->ViewListLock);
1757 KeInitializeMutex(&Section->Lock, 0);
1758 Section->Flags = 0;
1759 Section->NrSegments = 1;
1760 Section->ImageBase = NULL;
1761 Section->EntryPoint = NULL;
1762 Section->StackReserve = 0;
1763 Section->StackCommit = 0;
1764 Section->Subsystem = 0;
1765 Section->MinorSubsystemVersion = 0;
1766 Section->MajorSubsystemVersion = 0;
1767 Section->ImageCharacteristics = 0;
1768 Section->Machine = 0;
1769 Section->Executable = FALSE;
1770
1771 /*
1772 * Check file access required
1773 */
1774 if (SectionPageProtection & PAGE_READWRITE ||
1775 SectionPageProtection & PAGE_EXECUTE_READWRITE)
1776 {
1777 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
1778 }
1779 else
1780 {
1781 FileAccess = FILE_READ_DATA;
1782 }
1783
1784 /*
1785 * Reference the file handle
1786 */
1787 Status = ObReferenceObjectByHandle(FileHandle,
1788 FileAccess,
1789 IoFileObjectType,
1790 UserMode,
1791 (PVOID*)&FileObject,
1792 NULL);
1793 if (!NT_SUCCESS(Status))
1794 {
1795 ZwClose(*SectionHandle);
1796 ObDereferenceObject(Section);
1797 return(Status);
1798 }
1799
1800 /*
1801 * We can't do memory mappings if the file system doesn't support the
1802 * standard FCB
1803 */
1804 if (!(FileObject->Flags & FO_FCB_IS_VALID))
1805 {
1806 ZwClose(*SectionHandle);
1807 ObDereferenceObject(Section);
1808 ObDereferenceObject(FileObject);
1809 return(STATUS_INVALID_FILE_FOR_SECTION);
1810 }
1811
1812 /*
1813 * FIXME: Revise this once a locking order for file size changes is
1814 * decided
1815 */
1816 if (UMaximumSize != NULL)
1817 {
1818 MaximumSize = *UMaximumSize;
1819 }
1820 else
1821 {
1822 MaximumSize =
1823 ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
1824 }
1825
1826 /*
1827 * Lock the file
1828 */
1829 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
1830 0,
1831 KernelMode,
1832 FALSE,
1833 NULL);
1834 if (Status != STATUS_SUCCESS)
1835 {
1836 ZwClose(*SectionHandle);
1837 ObDereferenceObject(Section);
1838 ObDereferenceObject(FileObject);
1839 return(Status);
1840 }
1841
1842 /*
1843 * If this file hasn't been mapped as a data file before then allocate a
1844 * section segment to describe the data file mapping
1845 */
1846 if (FileObject->SectionObjectPointers->DataSectionObject == NULL)
1847 {
1848 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
1849 TAG_MM_SECTION_SEGMENT);
1850 if (Segment == NULL)
1851 {
1852 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
1853 ZwClose(*SectionHandle);
1854 ObDereferenceObject(Section);
1855 ObDereferenceObject(FileObject);
1856 return(STATUS_NO_MEMORY);
1857 }
1858 Section->Segments = Segment;
1859 Segment->ReferenceCount = 1;
1860 KeInitializeMutex(&Segment->Lock, 0);
1861
1862 /*
1863 * Set the lock before assigning the segment to the file object
1864 */
1865 Status = KeWaitForSingleObject((PVOID)&Segment->Lock,
1866 0,
1867 KernelMode,
1868 FALSE,
1869 NULL);
1870 if (Status != STATUS_SUCCESS)
1871 {
1872 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
1873 ExFreePool(Segment);
1874 ZwClose(*SectionHandle);
1875 ObDereferenceObject(Section);
1876 ObDereferenceObject(FileObject);
1877 return(Status);
1878 }
1879 FileObject->SectionObjectPointers->DataSectionObject = (PVOID)Segment;
1880
1881 Segment->FileOffset = 0;
1882 Segment->Protection = 0;
1883 Segment->Attributes = 0;
1884 Segment->Flags = 0;
1885 Segment->Characteristics = 0;
1886 Segment->WriteCopy = FALSE;
1887 if (AllocationAttributes & SEC_RESERVE)
1888 {
1889 Segment->Length = 0;
1890 }
1891 else
1892 {
1893 Segment->Length = MaximumSize.u.LowPart;
1894 }
1895 Segment->VirtualAddress = NULL;
1896 }
1897 else
1898 {
1899 /*
1900 * If the file is already mapped as a data file then we may need
1901 * to extend it
1902 */
1903 Segment =
1904 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers->
1905 DataSectionObject;
1906 Section->Segments = Segment;
1907 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
1908 Status = KeWaitForSingleObject((PVOID)&Section->Lock,
1909 0,
1910 KernelMode,
1911 FALSE,
1912 NULL);
1913 if (Status != STATUS_SUCCESS)
1914 {
1915 InterlockedDecrement((PLONG)&Segment->ReferenceCount);
1916 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
1917 ZwClose(*SectionHandle);
1918 ObDereferenceObject(Section);
1919 ObDereferenceObject(FileObject);
1920 return(Status);
1921 }
1922 if (MaximumSize.u.LowPart > Segment->Length &&
1923 !(AllocationAttributes & SEC_RESERVE))
1924 {
1925 Segment->Length = MaximumSize.u.LowPart;
1926 }
1927 }
1928 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
1929 Section->FileObject = FileObject;
1930 KeReleaseMutex(&Segment->Lock, FALSE);
1931
1932 ObDereferenceObject(Section);
1933 return(STATUS_SUCCESS);
1934 }
1935
1936 static ULONG SectionCharacteristicsToProtect[16] =
1937 {
1938 PAGE_NOACCESS, // 0 = NONE
1939 PAGE_NOACCESS, // 1 = SHARED
1940 PAGE_EXECUTE, // 2 = EXECUTABLE
1941 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
1942 PAGE_READONLY, // 4 = READABLE
1943 PAGE_READONLY, // 5 = READABLE, SHARED
1944 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
1945 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
1946 PAGE_READWRITE, // 8 = WRITABLE
1947 PAGE_READWRITE, // 9 = WRITABLE, SHARED
1948 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
1949 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
1950 PAGE_READWRITE, // 12 = WRITABLE, READABLE
1951 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
1952 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
1953 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
1954 };
1955
1956 NTSTATUS
1957 MmCreateImageSection(PHANDLE SectionHandle,
1958 ACCESS_MASK DesiredAccess,
1959 POBJECT_ATTRIBUTES ObjectAttributes,
1960 PLARGE_INTEGER UMaximumSize,
1961 ULONG SectionPageProtection,
1962 ULONG AllocationAttributes,
1963 HANDLE FileHandle)
1964 {
1965 PSECTION_OBJECT Section;
1966 NTSTATUS Status;
1967 PFILE_OBJECT FileObject;
1968 ULONG FileAccess;
1969 IMAGE_DOS_HEADER DosHeader;
1970 IO_STATUS_BLOCK Iosb;
1971 LARGE_INTEGER Offset;
1972 IMAGE_NT_HEADERS PEHeader;
1973 PIMAGE_SECTION_HEADER ImageSections;
1974 PMM_SECTION_SEGMENT SectionSegments;
1975 ULONG NrSegments;
1976 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
1977
1978 /*
1979 * Check the protection
1980 */
1981 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
1982 SectionPageProtection)
1983 {
1984 return(STATUS_INVALID_PAGE_PROTECTION);
1985 }
1986
1987 /*
1988 * Specifying a maximum size is meaningless for an image section
1989 */
1990 if (UMaximumSize != NULL)
1991 {
1992 return(STATUS_INVALID_PARAMETER_4);
1993 }
1994
1995 /*
1996 * Read the dos header
1997 */
1998 Offset.QuadPart = 0;
1999 Status = ZwReadFile(FileHandle,
2000 NULL,
2001 NULL,
2002 NULL,
2003 &Iosb,
2004 &DosHeader,
2005 sizeof(DosHeader),
2006 &Offset,
2007 0);
2008 if (!NT_SUCCESS(Status))
2009 {
2010 return(Status);
2011 }
2012 if (Iosb.Information != sizeof(DosHeader))
2013 {
2014 return(STATUS_INVALID_IMAGE_FORMAT);
2015 }
2016
2017 /*
2018 * Check the DOS signature
2019 */
2020 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2021 {
2022 return(STATUS_INVALID_IMAGE_FORMAT);
2023 }
2024
2025 /*
2026 * Read the PE header
2027 */
2028 Offset.QuadPart = DosHeader.e_lfanew;
2029 Status = ZwReadFile(FileHandle,
2030 NULL,
2031 NULL,
2032 NULL,
2033 &Iosb,
2034 &PEHeader,
2035 sizeof(PEHeader),
2036 &Offset,
2037 0);
2038 if (!NT_SUCCESS(Status))
2039 {
2040 return(Status);
2041 }
2042 if (Iosb.Information != sizeof(PEHeader))
2043 {
2044 return(STATUS_INVALID_IMAGE_FORMAT);
2045 }
2046
2047 /*
2048 * Check the signature
2049 */
2050 if (PEHeader.Signature != IMAGE_NT_SIGNATURE)
2051 {
2052 return(STATUS_INVALID_IMAGE_FORMAT);
2053 }
2054
2055 /*
2056 * Read in the section headers
2057 */
2058 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2059 ImageSections =
2060 ExAllocatePool(NonPagedPool,
2061 PEHeader.FileHeader.NumberOfSections *
2062 sizeof(IMAGE_SECTION_HEADER));
2063 Status = ZwReadFile(FileHandle,
2064 NULL,
2065 NULL,
2066 NULL,
2067 &Iosb,
2068 ImageSections,
2069 PEHeader.FileHeader.NumberOfSections *
2070 sizeof(IMAGE_SECTION_HEADER),
2071 &Offset,
2072 0);
2073 if (!NT_SUCCESS(Status))
2074 {
2075 ExFreePool(ImageSections);
2076 return(Status);
2077 }
2078 if (Iosb.Information !=
2079 (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2080 {
2081 ExFreePool(ImageSections);
2082 return(STATUS_INVALID_IMAGE_FORMAT);
2083 }
2084
2085 /*
2086 * Create the section
2087 */
2088 Status = ObCreateObject(SectionHandle,
2089 DesiredAccess,
2090 ObjectAttributes,
2091 MmSectionObjectType,
2092 (PVOID*)&Section);
2093 if (!NT_SUCCESS(Status))
2094 {
2095 ExFreePool(ImageSections);
2096 return(Status);
2097 }
2098
2099 /*
2100 * Initialize it
2101 */
2102 Section->SectionPageProtection = SectionPageProtection;
2103 Section->AllocateAttributes = AllocationAttributes;
2104 InitializeListHead(&Section->ViewListHead);
2105 KeInitializeSpinLock(&Section->ViewListLock);
2106 KeInitializeMutex(&Section->Lock, 0);
2107 Section->Flags = MM_IMAGE_SECTION;
2108 Section->NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2109 Section->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2110 Section->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2111 Section->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2112 Section->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2113 Section->Subsystem = PEHeader.OptionalHeader.Subsystem;
2114 Section->MinorSubsystemVersion =
2115 PEHeader.OptionalHeader.MinorSubsystemVersion;
2116 Section->MajorSubsystemVersion =
2117 PEHeader.OptionalHeader.MajorSubsystemVersion;
2118 Section->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2119 Section->Machine = PEHeader.FileHeader.Machine;
2120 Section->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2121
2122 /*
2123 * Check file access required
2124 */
2125 if (SectionPageProtection & PAGE_READWRITE ||
2126 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2127 {
2128 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2129 }
2130 else
2131 {
2132 FileAccess = FILE_READ_DATA;
2133 }
2134
2135 /*
2136 * Reference the file handle
2137 */
2138 Status = ObReferenceObjectByHandle(FileHandle,
2139 FileAccess,
2140 IoFileObjectType,
2141 UserMode,
2142 (PVOID*)&FileObject,
2143 NULL);
2144 if (!NT_SUCCESS(Status))
2145 {
2146 ZwClose(*SectionHandle);
2147 ObDereferenceObject(Section);
2148 ExFreePool(ImageSections);
2149 return(Status);
2150 }
2151
2152 /*
2153 * We can't do memory mappings if the file system doesn't support the
2154 * standard FCB
2155 */
2156 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2157 {
2158 ZwClose(*SectionHandle);
2159 ObDereferenceObject(Section);
2160 ObDereferenceObject(FileObject);
2161 ExFreePool(ImageSections);
2162 return(STATUS_INVALID_FILE_FOR_SECTION);
2163 }
2164
2165 /*
2166 * Lock the file
2167 */
2168 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2169 0,
2170 KernelMode,
2171 FALSE,
2172 NULL);
2173 if (Status != STATUS_SUCCESS)
2174 {
2175 ZwClose(*SectionHandle);
2176 ObDereferenceObject(Section);
2177 ObDereferenceObject(FileObject);
2178 ExFreePool(ImageSections);
2179 return(Status);
2180 }
2181
2182 /*
2183 * If this file hasn't been mapped as a image file before then allocate the
2184 * section segments to describe the mapping
2185 */
2186 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2187 if (FileObject->SectionObjectPointers->ImageSectionObject == NULL)
2188 {
2189 ULONG i;
2190 ULONG Size;
2191
2192 Size = sizeof(MM_IMAGE_SECTION_OBJECT) +
2193 (sizeof(MM_SECTION_SEGMENT) * NrSegments);
2194 ImageSectionObject =
2195 ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2196 if (ImageSectionObject == NULL)
2197 {
2198 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2199 ZwClose(*SectionHandle);
2200 ObDereferenceObject(Section);
2201 ObDereferenceObject(FileObject);
2202 ExFreePool(ImageSections);
2203 return(STATUS_NO_MEMORY);
2204 }
2205 ImageSectionObject->NrSegments = NrSegments;
2206 SectionSegments = ImageSectionObject->Segments;
2207 Section->Segments = SectionSegments;
2208
2209 SectionSegments[0].FileOffset = 0;
2210 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2211 SectionSegments[0].Protection = PAGE_READWRITE;
2212 SectionSegments[0].RawLength = PAGESIZE;
2213 SectionSegments[0].Length = PAGESIZE;
2214 SectionSegments[0].Flags = 0;
2215 SectionSegments[0].ReferenceCount = 1;
2216 SectionSegments[0].VirtualAddress = 0;
2217 SectionSegments[0].WriteCopy = TRUE;
2218 KeInitializeMutex(&SectionSegments[0].Lock, 0);
2219
2220 for (i = 1; i < NrSegments; i++)
2221 {
2222 SectionSegments[i].FileOffset =
2223 ImageSections[i-1].PointerToRawData;
2224 SectionSegments[i].Characteristics =
2225 ImageSections[i-1].Characteristics;
2226
2227 /*
2228 * Set up the protection and write copy variables.
2229 */
2230 if ((ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_READABLE) ||
2231 (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_WRITABLE) ||
2232 (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE))
2233 {
2234 SectionSegments[i].Protection =
2235 SectionCharacteristicsToProtect[ImageSections[i-1].Characteristics >> 28];
2236 SectionSegments[i].WriteCopy =
2237 !(ImageSections[i - 1].Characteristics & IMAGE_SECTION_CHAR_SHARED);
2238 }
2239 else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_CODE)
2240 {
2241 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2242 SectionSegments[i].WriteCopy = TRUE;
2243 }
2244 else if (ImageSections[i-1].Characteristics &
2245 IMAGE_SECTION_CHAR_DATA)
2246 {
2247 SectionSegments[i].Protection = PAGE_READWRITE;
2248 SectionSegments[i].WriteCopy = TRUE;
2249 }
2250 else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_BSS)
2251 {
2252 SectionSegments[i].Protection = PAGE_READWRITE;
2253 SectionSegments[i].WriteCopy = TRUE;
2254 }
2255 else
2256 {
2257 SectionSegments[i].Protection = PAGE_NOACCESS;
2258 SectionSegments[i].WriteCopy = TRUE;
2259 }
2260
2261 /*
2262 * Set up the attributes.
2263 */
2264 if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_CODE)
2265 {
2266 SectionSegments[i].Attributes = 0;
2267 }
2268 else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_DATA)
2269 {
2270 SectionSegments[i].Attributes = 0;
2271 }
2272 else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_BSS)
2273 {
2274 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2275 }
2276 else
2277 {
2278 SectionSegments[i].Attributes = 0;
2279 }
2280
2281 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2282 SectionSegments[i].Length =
2283 ImageSections[i-1].Misc.VirtualSize;
2284 SectionSegments[i].Flags = 0;
2285 SectionSegments[i].ReferenceCount = 1;
2286 SectionSegments[i].VirtualAddress =
2287 (PVOID)ImageSections[i-1].VirtualAddress;
2288 KeInitializeMutex(&SectionSegments[i].Lock, 0);
2289 }
2290
2291 FileObject->SectionObjectPointers->ImageSectionObject =
2292 (PVOID)ImageSectionObject;
2293 }
2294 else
2295 {
2296 ULONG i;
2297
2298 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)
2299 FileObject->SectionObjectPointers->ImageSectionObject;
2300 SectionSegments = ImageSectionObject->Segments;
2301 Section->Segments = SectionSegments;
2302
2303 /*
2304 * Otherwise just reference all the section segments
2305 */
2306 for (i = 0; i < NrSegments; i++)
2307 {
2308 InterlockedIncrement(&SectionSegments[i].ReferenceCount);
2309 }
2310
2311 }
2312 ExFreePool(ImageSections);
2313 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2314 Section->FileObject = FileObject;
2315
2316 ObDereferenceObject(Section);
2317 return(STATUS_SUCCESS);
2318 }
2319
2320 NTSTATUS STDCALL
2321 NtCreateSection (OUT PHANDLE SectionHandle,
2322 IN ACCESS_MASK DesiredAccess,
2323 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2324 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2325 IN ULONG SectionPageProtection OPTIONAL,
2326 IN ULONG AllocationAttributes,
2327 IN HANDLE FileHandle OPTIONAL)
2328 {
2329 if (AllocationAttributes & SEC_IMAGE)
2330 {
2331 return(MmCreateImageSection(SectionHandle,
2332 DesiredAccess,
2333 ObjectAttributes,
2334 MaximumSize,
2335 SectionPageProtection,
2336 AllocationAttributes,
2337 FileHandle));
2338 }
2339 else if (FileHandle != NULL)
2340 {
2341 return(MmCreateDataFileSection(SectionHandle,
2342 DesiredAccess,
2343 ObjectAttributes,
2344 MaximumSize,
2345 SectionPageProtection,
2346 AllocationAttributes,
2347 FileHandle));
2348 }
2349 else
2350 {
2351 return(MmCreatePageFileSection(SectionHandle,
2352 DesiredAccess,
2353 ObjectAttributes,
2354 MaximumSize,
2355 SectionPageProtection,
2356 AllocationAttributes));
2357 }
2358 }
2359
2360
2361 /**********************************************************************
2362 * NAME
2363 * NtOpenSection
2364 *
2365 * DESCRIPTION
2366 *
2367 * ARGUMENTS
2368 * SectionHandle
2369 *
2370 * DesiredAccess
2371 *
2372 * ObjectAttributes
2373 *
2374 * RETURN VALUE
2375 *
2376 * REVISIONS
2377 *
2378 */
2379 NTSTATUS STDCALL
2380 NtOpenSection(PHANDLE SectionHandle,
2381 ACCESS_MASK DesiredAccess,
2382 POBJECT_ATTRIBUTES ObjectAttributes)
2383 {
2384 NTSTATUS Status;
2385
2386 *SectionHandle = 0;
2387
2388 Status = ObOpenObjectByName(ObjectAttributes,
2389 MmSectionObjectType,
2390 NULL,
2391 UserMode,
2392 DesiredAccess,
2393 NULL,
2394 SectionHandle);
2395
2396 return(Status);
2397 }
2398
2399 NTSTATUS
2400 MmMapViewOfSegment(PEPROCESS Process,
2401 PMADDRESS_SPACE AddressSpace,
2402 PSECTION_OBJECT Section,
2403 PMM_SECTION_SEGMENT Segment,
2404 PVOID* BaseAddress,
2405 ULONG ViewSize,
2406 ULONG Protect,
2407 ULONG ViewOffset)
2408 {
2409 PMEMORY_AREA MArea;
2410 NTSTATUS Status;
2411 KIRQL oldIrql;
2412
2413 MmLockAddressSpace(&Process->AddressSpace);
2414 if (Protect == PAGE_NOACCESS || Protect == PAGE_GUARD)
2415 {
2416 DPRINT1("Mapping inaccessible region between 0x%.8X and 0x%.8X\n",
2417 (*BaseAddress), (*BaseAddress) + ViewSize);
2418 }
2419 Status = MmCreateMemoryArea(Process,
2420 &Process->AddressSpace,
2421 MEMORY_AREA_SECTION_VIEW_COMMIT,
2422 BaseAddress,
2423 ViewSize,
2424 Protect,
2425 &MArea,
2426 FALSE);
2427 MmUnlockAddressSpace(&Process->AddressSpace);
2428 if (!NT_SUCCESS(Status))
2429 {
2430 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2431 (*BaseAddress), (*BaseAddress) + ViewSize);
2432 return(Status);
2433 }
2434
2435 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2436 InsertTailList(&Section->ViewListHead,
2437 &MArea->Data.SectionData.ViewListEntry);
2438 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2439
2440 ObReferenceObjectByPointer((PVOID)Section,
2441 SECTION_MAP_READ,
2442 NULL,
2443 ExGetPreviousMode());
2444 MArea->Data.SectionData.Segment = Segment;
2445 MArea->Data.SectionData.Section = Section;
2446 MArea->Data.SectionData.ViewOffset = ViewOffset;
2447 MArea->Data.SectionData.WriteCopyView = FALSE;
2448
2449 return(STATUS_SUCCESS);
2450 }
2451
2452
2453 /**********************************************************************
2454 * NAME EXPORTED
2455 * NtMapViewOfSection
2456 *
2457 * DESCRIPTION
2458 * Maps a view of a section into the virtual address space of a
2459 * process.
2460 *
2461 * ARGUMENTS
2462 * SectionHandle
2463 * Handle of the section.
2464 *
2465 * ProcessHandle
2466 * Handle of the process.
2467 *
2468 * BaseAddress
2469 * Desired base address (or NULL) on entry;
2470 * Actual base address of the view on exit.
2471 *
2472 * ZeroBits
2473 * Number of high order address bits that must be zero.
2474 *
2475 * CommitSize
2476 * Size in bytes of the initially committed section of
2477 * the view.
2478 *
2479 * SectionOffset
2480 * Offset in bytes from the beginning of the section
2481 * to the beginning of the view.
2482 *
2483 * ViewSize
2484 * Desired length of map (or zero to map all) on entry
2485 * Actual length mapped on exit.
2486 *
2487 * InheritDisposition
2488 * Specified how the view is to be shared with
2489 * child processes.
2490 *
2491 * AllocateType
2492 * Type of allocation for the pages.
2493 *
2494 * Protect
2495 * Protection for the committed region of the view.
2496 *
2497 * RETURN VALUE
2498 * Status.
2499 */
2500 NTSTATUS STDCALL
2501 NtMapViewOfSection(HANDLE SectionHandle,
2502 HANDLE ProcessHandle,
2503 PVOID* BaseAddress,
2504 ULONG ZeroBits,
2505 ULONG CommitSize,
2506 PLARGE_INTEGER SectionOffset,
2507 PULONG ViewSize,
2508 SECTION_INHERIT InheritDisposition,
2509 ULONG AllocationType,
2510 ULONG Protect)
2511 {
2512 PSECTION_OBJECT Section;
2513 PEPROCESS Process;
2514 NTSTATUS Status;
2515 PMADDRESS_SPACE AddressSpace;
2516
2517 Status = ObReferenceObjectByHandle(ProcessHandle,
2518 PROCESS_VM_OPERATION,
2519 PsProcessType,
2520 UserMode,
2521 (PVOID*)&Process,
2522 NULL);
2523 if (!NT_SUCCESS(Status))
2524 {
2525 return(Status);
2526 }
2527
2528 AddressSpace = &Process->AddressSpace;
2529
2530 Status = ObReferenceObjectByHandle(SectionHandle,
2531 SECTION_MAP_READ,
2532 MmSectionObjectType,
2533 UserMode,
2534 (PVOID*)&Section,
2535 NULL);
2536 if (!(NT_SUCCESS(Status)))
2537 {
2538 DPRINT("ObReference failed rc=%x\n",Status);
2539 ObDereferenceObject(Process);
2540 return(Status);
2541 }
2542
2543 Status = MmMapViewOfSection(Section,
2544 Process,
2545 BaseAddress,
2546 ZeroBits,
2547 CommitSize,
2548 SectionOffset,
2549 ViewSize,
2550 InheritDisposition,
2551 AllocationType,
2552 Protect);
2553
2554 ObDereferenceObject(Section);
2555 ObDereferenceObject(Process);
2556
2557 return(Status);
2558 }
2559
2560 VOID STATIC
2561 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, ULONG PhysAddr,
2562 SWAPENTRY SwapEntry, BOOLEAN Dirty)
2563 {
2564 PMEMORY_AREA MArea;
2565 ULONG Entry;
2566
2567 MArea = (PMEMORY_AREA)Context;
2568
2569 if (SwapEntry != 0)
2570 {
2571 MmFreeSwapPage(SwapEntry);
2572 }
2573 else if (PhysAddr != 0)
2574 {
2575 ULONG Offset;
2576
2577 Offset =
2578 ((ULONG)PAGE_ROUND_DOWN(Address) - (ULONG)MArea->BaseAddress) +
2579 MArea->Data.SectionData.ViewOffset;
2580
2581 Entry = MmGetPageEntrySectionSegment(MArea->Data.SectionData.Segment,
2582 Offset);
2583 if (IS_SWAP_FROM_SSE(Entry))
2584 {
2585 KeBugCheck(0);
2586 }
2587 else if (PhysAddr != (PAGE_FROM_SSE(Entry)))
2588 {
2589 /*
2590 * Just dereference private pages
2591 */
2592 MmDeleteRmap((PVOID)PhysAddr, MArea->Process, Address);
2593 MmDereferencePage((PVOID)PhysAddr);
2594 }
2595 else
2596 {
2597 MmUnsharePageEntrySectionSegment(MArea->Data.SectionData.Section,
2598 MArea->Data.SectionData.Segment,
2599 Offset,
2600 Dirty);
2601 MmDeleteRmap((PVOID)PhysAddr, MArea->Process, Address);
2602 MmDereferencePage((PVOID)PhysAddr);
2603 }
2604 }
2605 }
2606
2607 NTSTATUS STDCALL
2608 MmUnmapViewOfSection(PEPROCESS Process,
2609 PVOID BaseAddress)
2610 {
2611 NTSTATUS Status;
2612 PMEMORY_AREA MemoryArea;
2613 PMADDRESS_SPACE AddressSpace;
2614 PSECTION_OBJECT Section;
2615 PMM_SECTION_SEGMENT Segment;
2616 KIRQL oldIrql;
2617
2618 AddressSpace = &Process->AddressSpace;
2619
2620 DPRINT("Opening memory area Process %x BaseAddress %x\n",
2621 Process, BaseAddress);
2622 MmLockAddressSpace(AddressSpace);
2623 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
2624 BaseAddress);
2625 if (MemoryArea == NULL)
2626 {
2627 MmUnlockAddressSpace(AddressSpace);
2628 return(STATUS_UNSUCCESSFUL);
2629 }
2630
2631 MmLockSection(MemoryArea->Data.SectionData.Section);
2632 MmLockSectionSegment(MemoryArea->Data.SectionData.Segment);
2633 Section = MemoryArea->Data.SectionData.Section;
2634 Segment = MemoryArea->Data.SectionData.Segment;
2635 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2636 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
2637 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2638 if (MemoryArea->Data.SectionData.Section->Flags & SO_PHYSICAL_MEMORY)
2639 {
2640 Status = MmFreeMemoryArea(&Process->AddressSpace,
2641 BaseAddress,
2642 0,
2643 NULL,
2644 NULL);
2645 }
2646 else
2647 {
2648 Status = MmFreeMemoryArea(&Process->AddressSpace,
2649 BaseAddress,
2650 0,
2651 MmFreeSectionPage,
2652 MemoryArea);
2653 }
2654 MmUnlockSection(Section);
2655 MmUnlockSectionSegment(Segment);
2656 ObDereferenceObject(Section);
2657 MmUnlockAddressSpace(AddressSpace);
2658 return(STATUS_SUCCESS);
2659 }
2660
2661 /**********************************************************************
2662 * NAME EXPORTED
2663 * NtUnmapViewOfSection
2664 *
2665 * DESCRIPTION
2666 *
2667 * ARGUMENTS
2668 * ProcessHandle
2669 *
2670 * BaseAddress
2671 *
2672 * RETURN VALUE
2673 * Status.
2674 *
2675 * REVISIONS
2676 *
2677 */
2678 NTSTATUS STDCALL
2679 NtUnmapViewOfSection (HANDLE ProcessHandle,
2680 PVOID BaseAddress)
2681 {
2682 PEPROCESS Process;
2683 NTSTATUS Status;
2684
2685 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
2686 ProcessHandle, BaseAddress);
2687
2688 DPRINT("Referencing process\n");
2689 Status = ObReferenceObjectByHandle(ProcessHandle,
2690 PROCESS_VM_OPERATION,
2691 PsProcessType,
2692 UserMode,
2693 (PVOID*)&Process,
2694 NULL);
2695 if (!NT_SUCCESS(Status))
2696 {
2697 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
2698 return(Status);
2699 }
2700
2701 Status = MmUnmapViewOfSection(Process, BaseAddress);
2702
2703 ObDereferenceObject(Process);
2704
2705 return Status;
2706 }
2707
2708
2709 NTSTATUS STDCALL
2710 NtQuerySection (IN HANDLE SectionHandle,
2711 IN CINT SectionInformationClass,
2712 OUT PVOID SectionInformation,
2713 IN ULONG Length,
2714 OUT PULONG ResultLength)
2715 /*
2716 * FUNCTION: Queries the information of a section object.
2717 * ARGUMENTS:
2718 * SectionHandle = Handle to the section link object
2719 * SectionInformationClass = Index to a certain information structure
2720 * SectionInformation (OUT)= Caller supplies storage for resulting
2721 * information
2722 * Length = Size of the supplied storage
2723 * ResultLength = Data written
2724 * RETURNS: Status
2725 *
2726 */
2727 {
2728 PSECTION_OBJECT Section;
2729 NTSTATUS Status;
2730
2731 Status = ObReferenceObjectByHandle(SectionHandle,
2732 SECTION_MAP_READ,
2733 MmSectionObjectType,
2734 UserMode,
2735 (PVOID*)&Section,
2736 NULL);
2737 if (!(NT_SUCCESS(Status)))
2738 {
2739 return(Status);
2740 }
2741
2742 switch (SectionInformationClass)
2743 {
2744 case SectionBasicInformation:
2745 {
2746 PSECTION_BASIC_INFORMATION Sbi;
2747
2748 if (Length != sizeof(SECTION_BASIC_INFORMATION))
2749 {
2750 ObDereferenceObject(Section);
2751 return(STATUS_INFO_LENGTH_MISMATCH);
2752 }
2753
2754 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
2755
2756 Sbi->BaseAddress = 0;
2757 Sbi->Attributes = 0;
2758 Sbi->Size.QuadPart = 0;
2759
2760 Status = STATUS_SUCCESS;
2761
2762 break;
2763 }
2764
2765 case SectionImageInformation:
2766 {
2767 PSECTION_IMAGE_INFORMATION Sii;
2768
2769 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
2770 {
2771 ObDereferenceObject(Section);
2772 return(STATUS_INFO_LENGTH_MISMATCH);
2773 }
2774 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
2775 Sii->EntryPoint = Section->EntryPoint;
2776 Sii->Unknown1 = 0;
2777 Sii->StackReserve = Section->StackReserve;
2778 Sii->StackCommit = Section->StackCommit;
2779 Sii->Subsystem = Section->Subsystem;
2780 Sii->MinorSubsystemVersion = Section->MinorSubsystemVersion;
2781 Sii->MajorSubsystemVersion = Section->MajorSubsystemVersion;
2782 Sii->Unknown2 = 0;
2783 Sii->Characteristics = Section->ImageCharacteristics;
2784 Sii->ImageNumber = Section->Machine;
2785 Sii->Executable = Section->Executable;
2786 Sii->Unknown3 = 0;
2787 Sii->Unknown4[0] = 0;
2788 Sii->Unknown4[1] = 0;
2789 Sii->Unknown4[2] = 0;
2790
2791 Status = STATUS_SUCCESS;
2792 break;
2793 }
2794
2795 default:
2796 Status = STATUS_INVALID_INFO_CLASS;
2797 }
2798 ObDereferenceObject(Section);
2799 return(Status);
2800 }
2801
2802
2803 NTSTATUS STDCALL
2804 NtExtendSection(IN HANDLE SectionHandle,
2805 IN ULONG NewMaximumSize)
2806 {
2807 UNIMPLEMENTED;
2808 }
2809
2810
2811 /**********************************************************************
2812 * NAME INTERNAL
2813 * MmAllocateSection@4
2814 *
2815 * DESCRIPTION
2816 *
2817 * ARGUMENTS
2818 * Length
2819 *
2820 * RETURN VALUE
2821 *
2822 * NOTE
2823 * Code taken from ntoskrnl/mm/special.c.
2824 *
2825 * REVISIONS
2826 *
2827 */
2828 PVOID STDCALL
2829 MmAllocateSection (IN ULONG Length)
2830 {
2831 PVOID Result;
2832 MEMORY_AREA* marea;
2833 NTSTATUS Status;
2834 ULONG i;
2835 PMADDRESS_SPACE AddressSpace;
2836
2837 DPRINT("MmAllocateSection(Length %x)\n",Length);
2838
2839 AddressSpace = MmGetKernelAddressSpace();
2840 Result = NULL;
2841 MmLockAddressSpace(AddressSpace);
2842 Status = MmCreateMemoryArea (NULL,
2843 AddressSpace,
2844 MEMORY_AREA_SYSTEM,
2845 &Result,
2846 Length,
2847 0,
2848 &marea,
2849 FALSE);
2850 if (!NT_SUCCESS(Status))
2851 {
2852 MmUnlockAddressSpace(AddressSpace);
2853 return (NULL);
2854 }
2855 MmUnlockAddressSpace(AddressSpace);
2856 DPRINT("Result %p\n",Result);
2857 for (i = 0; (i <= (Length / PAGESIZE)); i++)
2858 {
2859 PVOID Page;
2860
2861 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
2862 if (!NT_SUCCESS(Status))
2863 {
2864 DbgPrint("Unable to allocate page\n");
2865 KeBugCheck(0);
2866 }
2867 Status = MmCreateVirtualMapping (NULL,
2868 (Result + (i * PAGESIZE)),
2869 PAGE_READWRITE,
2870 (ULONG)Page,
2871 TRUE);
2872 if (!NT_SUCCESS(Status))
2873 {
2874 DbgPrint("Unable to create virtual mapping\n");
2875 KeBugCheck(0);
2876 }
2877 }
2878 return ((PVOID)Result);
2879 }
2880
2881
2882 /**********************************************************************
2883 * NAME EXPORTED
2884 * MmMapViewOfSection
2885 *
2886 * DESCRIPTION
2887 * Maps a view of a section into the virtual address space of a
2888 * process.
2889 *
2890 * ARGUMENTS
2891 * Section
2892 * Pointer to the section object.
2893 *
2894 * ProcessHandle
2895 * Pointer to the process.
2896 *
2897 * BaseAddress
2898 * Desired base address (or NULL) on entry;
2899 * Actual base address of the view on exit.
2900 *
2901 * ZeroBits
2902 * Number of high order address bits that must be zero.
2903 *
2904 * CommitSize
2905 * Size in bytes of the initially committed section of
2906 * the view.
2907 *
2908 * SectionOffset
2909 * Offset in bytes from the beginning of the section
2910 * to the beginning of the view.
2911 *
2912 * ViewSize
2913 * Desired length of map (or zero to map all) on entry
2914 * Actual length mapped on exit.
2915 *
2916 * InheritDisposition
2917 * Specified how the view is to be shared with
2918 * child processes.
2919 *
2920 * AllocationType
2921 * Type of allocation for the pages.
2922 *
2923 * Protect
2924 * Protection for the committed region of the view.
2925 *
2926 * RETURN VALUE
2927 * Status.
2928 */
2929 NTSTATUS STDCALL
2930 MmMapViewOfSection(IN PVOID SectionObject,
2931 IN PEPROCESS Process,
2932 IN OUT PVOID *BaseAddress,
2933 IN ULONG ZeroBits,
2934 IN ULONG CommitSize,
2935 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
2936 IN OUT PULONG ViewSize,
2937 IN SECTION_INHERIT InheritDisposition,
2938 IN ULONG AllocationType,
2939 IN ULONG Protect)
2940 {
2941 PSECTION_OBJECT Section;
2942 PMADDRESS_SPACE AddressSpace;
2943 ULONG ViewOffset;
2944 NTSTATUS Status;
2945
2946 Section = (PSECTION_OBJECT)SectionObject;
2947 AddressSpace = &Process->AddressSpace;
2948
2949 MmLockAddressSpace(AddressSpace);
2950 MmLockSection(SectionObject);
2951
2952 if (Section->Flags & MM_IMAGE_SECTION)
2953 {
2954 ULONG i;
2955
2956 for (i = 0; i < Section->NrSegments; i++)
2957 {
2958 PVOID SBaseAddress;
2959
2960 if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD))
2961 {
2962 SBaseAddress = (PVOID)
2963 ((ULONG)Section->ImageBase +
2964 (ULONG)Section->Segments[i].VirtualAddress);
2965
2966 MmLockSectionSegment(&Section->Segments[i]);
2967 Status = MmMapViewOfSegment(Process,
2968 &Process->AddressSpace,
2969 Section,
2970 &Section->Segments[i],
2971 &SBaseAddress,
2972 Section->Segments[i].Length,
2973 Section->Segments[i].Protection,
2974 Section->Segments[i].FileOffset);
2975 MmUnlockSectionSegment(&Section->Segments[i]);
2976 if (!NT_SUCCESS(Status))
2977 {
2978 MmUnlockSection(Section);
2979 MmUnlockAddressSpace(AddressSpace);
2980 return(Status);
2981 }
2982 }
2983 }
2984 *BaseAddress = Section->ImageBase;
2985 }
2986 else
2987 {
2988 if (SectionOffset == NULL)
2989 {
2990 ViewOffset = 0;
2991 }
2992 else
2993 {
2994 ViewOffset = SectionOffset->u.LowPart;
2995 }
2996
2997 if ((ViewOffset % PAGESIZE) != 0)
2998 {
2999 MmUnlockSection(Section);
3000 MmUnlockAddressSpace(AddressSpace);
3001 return(STATUS_MAPPED_ALIGNMENT);
3002 }
3003
3004 if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3005 {
3006 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3007 }
3008
3009 MmLockSectionSegment(Section->Segments);
3010 Status = MmMapViewOfSegment(Process,
3011 &Process->AddressSpace,
3012 Section,
3013 Section->Segments,
3014 BaseAddress,
3015 *ViewSize,
3016 Protect,
3017 ViewOffset);
3018 MmUnlockSectionSegment(Section->Segments);
3019 if (!NT_SUCCESS(Status))
3020 {
3021 MmUnlockSection(Section);
3022 MmUnlockAddressSpace(AddressSpace);
3023 return(Status);
3024 }
3025 }
3026
3027 MmUnlockSection(Section);
3028 MmUnlockAddressSpace(AddressSpace);
3029
3030 return(STATUS_SUCCESS);
3031 }
3032
3033
3034 BOOLEAN STDCALL
3035 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3036 IN PLARGE_INTEGER NewFileSize)
3037 {
3038 UNIMPLEMENTED;
3039 return (FALSE);
3040 }
3041
3042
3043 BOOLEAN STDCALL
3044 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3045 {
3046 UNIMPLEMENTED;
3047 return (FALSE);
3048 }
3049
3050 BOOLEAN STDCALL
3051 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3052 IN MMFLUSH_TYPE FlushType)
3053 {
3054 UNIMPLEMENTED;
3055 return (FALSE);
3056 }
3057
3058 BOOLEAN STDCALL
3059 MmForceSectionClosed (DWORD Unknown0,
3060 DWORD Unknown1)
3061 {
3062 UNIMPLEMENTED;
3063 return (FALSE);
3064 }
3065
3066
3067 NTSTATUS STDCALL
3068 MmMapViewInSystemSpace (IN PVOID Section,
3069 OUT PVOID * MappedBase,
3070 IN PULONG ViewSize)
3071 {
3072 UNIMPLEMENTED;
3073 return (STATUS_NOT_IMPLEMENTED);
3074 }
3075
3076 NTSTATUS STDCALL
3077 MmUnmapViewInSystemSpace (DWORD Unknown0)
3078 {
3079 UNIMPLEMENTED;
3080 return (STATUS_NOT_IMPLEMENTED);
3081 }
3082
3083
3084 NTSTATUS STDCALL
3085 MmSetBankedSection (DWORD Unknown0,
3086 DWORD Unknown1,
3087 DWORD Unknown2,
3088 DWORD Unknown3,
3089 DWORD Unknown4,
3090 DWORD Unknown5)
3091 {
3092 UNIMPLEMENTED;
3093 return (STATUS_NOT_IMPLEMENTED);
3094 }
3095
3096
3097 /**********************************************************************
3098 * NAME EXPORTED
3099 * MmCreateSection@
3100 *
3101 * DESCRIPTION
3102 * Creates a section object.
3103 *
3104 * ARGUMENTS
3105 * SectionObjiect (OUT)
3106 * Caller supplied storage for the resulting pointer
3107 * to a SECTION_BOJECT instance;
3108 *
3109 * DesiredAccess
3110 * Specifies the desired access to the section can be a
3111 * combination of:
3112 * STANDARD_RIGHTS_REQUIRED |
3113 * SECTION_QUERY |
3114 * SECTION_MAP_WRITE |
3115 * SECTION_MAP_READ |
3116 * SECTION_MAP_EXECUTE
3117 *
3118 * ObjectAttributes [OPTIONAL]
3119 * Initialized attributes for the object can be used
3120 * to create a named section;
3121 *
3122 * MaximumSize
3123 * Maximizes the size of the memory section. Must be
3124 * non-NULL for a page-file backed section.
3125 * If value specified for a mapped file and the file is
3126 * not large enough, file will be extended.
3127 *
3128 * SectionPageProtection
3129 * Can be a combination of:
3130 * PAGE_READONLY |
3131 * PAGE_READWRITE |
3132 * PAGE_WRITEONLY |
3133 * PAGE_WRITECOPY
3134 *
3135 * AllocationAttributes
3136 * Can be a combination of:
3137 * SEC_IMAGE |
3138 * SEC_RESERVE
3139 *
3140 * FileHandle
3141 * Handle to a file to create a section mapped to a file
3142 * instead of a memory backed section;
3143 *
3144 * File
3145 * Unknown.
3146 *
3147 * RETURN VALUE
3148 * Status.
3149 */
3150 NTSTATUS STDCALL
3151 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
3152 IN ACCESS_MASK DesiredAccess,
3153 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3154 IN PLARGE_INTEGER MaximumSize,
3155 IN ULONG SectionPageProtection,
3156 IN ULONG AllocationAttributes,
3157 IN HANDLE FileHandle OPTIONAL,
3158 IN PFILE_OBJECT File OPTIONAL)
3159 {
3160 return (STATUS_NOT_IMPLEMENTED);
3161 }
3162
3163 /* EOF */
3164
3165
3166
3167
3168
3169