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