2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sectopm.c
5 * PURPOSE: ARM Memory Manager Section Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARM³::SECTION"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* GLOBALS ********************************************************************/
21 ACCESS_MASK MmMakeSectionAccess
[8] =
26 SECTION_MAP_EXECUTE
| SECTION_MAP_READ
,
29 SECTION_MAP_EXECUTE
| SECTION_MAP_WRITE
,
30 SECTION_MAP_EXECUTE
| SECTION_MAP_READ
33 CHAR MmUserProtectionToMask1
[16] =
38 (CHAR
)MM_INVALID_PROTECTION
,
40 (CHAR
)MM_INVALID_PROTECTION
,
41 (CHAR
)MM_INVALID_PROTECTION
,
42 (CHAR
)MM_INVALID_PROTECTION
,
44 (CHAR
)MM_INVALID_PROTECTION
,
45 (CHAR
)MM_INVALID_PROTECTION
,
46 (CHAR
)MM_INVALID_PROTECTION
,
47 (CHAR
)MM_INVALID_PROTECTION
,
48 (CHAR
)MM_INVALID_PROTECTION
,
49 (CHAR
)MM_INVALID_PROTECTION
,
50 (CHAR
)MM_INVALID_PROTECTION
53 CHAR MmUserProtectionToMask2
[16] =
58 (CHAR
)MM_INVALID_PROTECTION
,
60 (CHAR
)MM_INVALID_PROTECTION
,
61 (CHAR
)MM_INVALID_PROTECTION
,
62 (CHAR
)MM_INVALID_PROTECTION
,
64 (CHAR
)MM_INVALID_PROTECTION
,
65 (CHAR
)MM_INVALID_PROTECTION
,
66 (CHAR
)MM_INVALID_PROTECTION
,
67 (CHAR
)MM_INVALID_PROTECTION
,
68 (CHAR
)MM_INVALID_PROTECTION
,
69 (CHAR
)MM_INVALID_PROTECTION
,
70 (CHAR
)MM_INVALID_PROTECTION
75 /* PRIVATE FUNCTIONS **********************************************************/
79 MiMakeProtectionMask(IN ULONG Protect
)
81 ULONG Mask1
, Mask2
, ProtectMask
;
83 /* PAGE_EXECUTE_WRITECOMBINE is theoretically the maximum */
84 if (Protect
>= (PAGE_WRITECOMBINE
* 2)) return MM_INVALID_PROTECTION
;
87 * Windows API protection mask can be understood as two bitfields, differing
88 * by whether or not execute rights are being requested
90 Mask1
= Protect
& 0xF;
91 Mask2
= (Protect
>> 4) & 0xF;
93 /* Check which field is there */
96 /* Mask2 must be there, use it to determine the PTE protection */
97 if (!Mask2
) return MM_INVALID_PROTECTION
;
98 ProtectMask
= MmUserProtectionToMask2
[Mask2
];
102 /* Mask2 should not be there, use Mask1 to determine the PTE mask */
103 if (Mask2
) return MM_INVALID_PROTECTION
;
104 ProtectMask
= MmUserProtectionToMask1
[Mask1
];
107 /* Make sure the final mask is a valid one */
108 if (ProtectMask
== MM_INVALID_PROTECTION
) return MM_INVALID_PROTECTION
;
110 /* Check for PAGE_GUARD option */
111 if (Protect
& PAGE_GUARD
)
113 /* It's not valid on no-access, nocache, or writecombine pages */
114 if ((ProtectMask
== MM_NOACCESS
) ||
115 (Protect
& (PAGE_NOCACHE
| PAGE_WRITECOMBINE
)))
117 /* Fail such requests */
118 return MM_INVALID_PROTECTION
;
121 /* This actually turns on guard page in this scenario! */
122 ProtectMask
|= MM_DECOMMIT
;
125 /* Check for nocache option */
126 if (Protect
& PAGE_NOCACHE
)
128 /* The earlier check should've eliminated this possibility */
129 ASSERT((Protect
& PAGE_GUARD
) == 0);
131 /* Check for no-access page or write combine page */
132 if ((ProtectMask
== MM_NOACCESS
) || (Protect
& PAGE_WRITECOMBINE
))
134 /* Such a request is invalid */
135 return MM_INVALID_PROTECTION
;
138 /* Add the PTE flag */
139 ProtectMask
|= MM_NOCACHE
;
142 /* Check for write combine option */
143 if (Protect
& PAGE_WRITECOMBINE
)
145 /* The two earlier scenarios should've caught this */
146 ASSERT((Protect
& (PAGE_GUARD
| PAGE_NOACCESS
)) == 0);
148 /* Don't allow on no-access pages */
149 if (ProtectMask
== MM_NOACCESS
) return MM_INVALID_PROTECTION
;
151 /* This actually turns on write-combine in this scenario! */
152 ProtectMask
|= MM_NOACCESS
;
155 /* Return the final MM PTE protection mask */
161 MiInitializeSystemSpaceMap(IN PVOID InputSession OPTIONAL
)
163 SIZE_T AllocSize
, BitmapSize
;
166 /* For now, always use the global session */
167 ASSERT(InputSession
== NULL
);
168 Session
= &MmSession
;
170 /* Initialize the system space lock */
171 Session
->SystemSpaceViewLockPointer
= &Session
->SystemSpaceViewLock
;
172 KeInitializeGuardedMutex(Session
->SystemSpaceViewLockPointer
);
174 /* Set the start address */
175 Session
->SystemSpaceViewStart
= MiSystemViewStart
;
177 /* Create a bitmap to describe system space */
178 BitmapSize
= sizeof(RTL_BITMAP
) + ((((MmSystemViewSize
/ MI_SYSTEM_VIEW_BUCKET_SIZE
) + 31) / 32) * sizeof(ULONG
));
179 Session
->SystemSpaceBitMap
= ExAllocatePoolWithTag(NonPagedPool
,
182 ASSERT(Session
->SystemSpaceBitMap
);
183 RtlInitializeBitMap(Session
->SystemSpaceBitMap
,
184 (PULONG
)(Session
->SystemSpaceBitMap
+ 1),
185 MmSystemViewSize
/ MI_SYSTEM_VIEW_BUCKET_SIZE
);
187 /* Set system space fully empty to begin with */
188 RtlClearAllBits(Session
->SystemSpaceBitMap
);
190 /* Set default hash flags */
191 Session
->SystemSpaceHashSize
= 31;
192 Session
->SystemSpaceHashKey
= Session
->SystemSpaceHashSize
- 1;
193 Session
->SystemSpaceHashEntries
= 0;
195 /* Calculate how much space for the hash views we'll need */
196 AllocSize
= sizeof(MMVIEW
) * Session
->SystemSpaceHashSize
;
197 ASSERT(AllocSize
< PAGE_SIZE
);
199 /* Allocate and zero the view table */
200 Session
->SystemSpaceViewTable
= ExAllocatePoolWithTag(NonPagedPool
,
203 ASSERT(Session
->SystemSpaceViewTable
!= NULL
);
204 RtlZeroMemory(Session
->SystemSpaceViewTable
, AllocSize
);
212 MiInsertInSystemSpace(IN PMMSESSION Session
,
214 IN PCONTROL_AREA ControlArea
)
217 ULONG Entry
, Hash
, i
;
220 /* Only global mappings supported for now */
221 ASSERT(Session
== &MmSession
);
223 /* Stay within 4GB and don't go past the number of hash entries available */
224 ASSERT(Buckets
< MI_SYSTEM_VIEW_BUCKET_SIZE
);
225 ASSERT(Session
->SystemSpaceHashEntries
< Session
->SystemSpaceHashSize
);
227 /* Find space where to map this view */
228 i
= RtlFindClearBitsAndSet(Session
->SystemSpaceBitMap
, Buckets
, 0);
229 ASSERT(i
!= 0xFFFFFFFF);
230 Base
= (PVOID
)((ULONG_PTR
)Session
->SystemSpaceViewStart
+ (i
* MI_SYSTEM_VIEW_BUCKET_SIZE
));
232 /* Get the hash entry for this allocation */
233 Entry
= ((ULONG_PTR
)Base
& ~(MI_SYSTEM_VIEW_BUCKET_SIZE
- 1)) + Buckets
;
234 Hash
= (Entry
>> 16) % Session
->SystemSpaceHashKey
;
236 /* Loop hash entries until a free one is found */
237 while (Session
->SystemSpaceViewTable
[Hash
].Entry
)
239 /* Unless we overflow, in which case loop back at hash o */
240 if (++Hash
>= Session
->SystemSpaceHashSize
) Hash
= 0;
243 /* Add this entry into the hash table */
244 Session
->SystemSpaceViewTable
[Hash
].Entry
= Entry
;
245 Session
->SystemSpaceViewTable
[Hash
].ControlArea
= ControlArea
;
247 /* Hash entry found, increment total and return the base address */
248 Session
->SystemSpaceHashEntries
++;
254 MiAddMappedPtes(IN PMMPTE FirstPte
,
255 IN PFN_NUMBER PteCount
,
256 IN PCONTROL_AREA ControlArea
)
259 PMMPTE PointerPte
, ProtoPte
, LastProtoPte
, LastPte
;
260 PSUBSECTION Subsection
;
262 /* ARM3 doesn't support this yet */
263 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
264 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
265 ASSERT(ControlArea
->FilePointer
== NULL
);
268 ASSERT(PteCount
!= 0);
269 ASSERT(ControlArea
->NumberOfMappedViews
>= 1);
270 ASSERT(ControlArea
->NumberOfUserReferences
>= 1);
271 ASSERT(ControlArea
->NumberOfSectionReferences
!= 0);
272 ASSERT(ControlArea
->u
.Flags
.BeingCreated
== 0);
273 ASSERT(ControlArea
->u
.Flags
.BeingDeleted
== 0);
274 ASSERT(ControlArea
->u
.Flags
.BeingPurged
== 0);
276 /* Get the PTEs for the actual mapping */
277 PointerPte
= FirstPte
;
278 LastPte
= FirstPte
+ PteCount
;
280 /* Get the prototype PTEs that desribe the section mapping in the subsection */
281 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
282 ProtoPte
= Subsection
->SubsectionBase
;
283 LastProtoPte
= &Subsection
->SubsectionBase
[Subsection
->PtesInSubsection
];
285 /* Loop the PTEs for the mapping */
286 while (PointerPte
< LastPte
)
288 /* We may have run out of prototype PTEs in this subsection */
289 if (ProtoPte
>= LastProtoPte
)
291 /* But we don't handle this yet */
296 /* The PTE should be completely clear */
297 ASSERT(PointerPte
->u
.Long
== 0);
299 /* Build the prototype PTE and write it */
300 MI_MAKE_PROTOTYPE_PTE(&TempPte
, ProtoPte
);
301 MI_WRITE_INVALID_PTE(PointerPte
, TempPte
);
308 /* No failure path */
309 return STATUS_SUCCESS
;
312 #if (_MI_PAGING_LEVELS == 2)
315 MiFillSystemPageDirectory(IN PVOID Base
,
316 IN SIZE_T NumberOfBytes
)
318 PMMPDE PointerPde
, LastPde
, SystemMapPde
;
320 PFN_NUMBER PageFrameIndex
;
324 /* Find the PDEs needed for this mapping */
325 PointerPde
= MiAddressToPde(Base
);
326 LastPde
= MiAddressToPde((PVOID
)((ULONG_PTR
)Base
+ NumberOfBytes
- 1));
328 /* Find the system double-mapped PDE that describes this mapping */
329 SystemMapPde
= &MmSystemPagePtes
[((ULONG_PTR
)PointerPde
& (SYSTEM_PD_SIZE
- 1)) / sizeof(MMPTE
)];
331 /* Use the PDE template and loop the PDEs */
332 TempPde
= ValidKernelPde
;
333 while (PointerPde
<= LastPde
)
335 /* Lock the PFN database */
336 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
338 /* Check if we don't already have this PDE mapped */
339 if (SystemMapPde
->u
.Hard
.Valid
== 0)
341 /* Grab a page for it */
342 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
343 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
344 PageFrameIndex
= MiRemoveZeroPage(MI_GET_NEXT_COLOR());
345 ASSERT(PageFrameIndex
);
346 TempPde
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
348 /* Initialize its PFN entry, with the parent system page directory page table */
349 MiInitializePfnForOtherProcess(PageFrameIndex
,
351 MmSystemPageDirectory
[(PointerPde
- MiAddressToPde(NULL
)) / PDE_COUNT
]);
353 /* Make the system PDE entry valid */
354 MI_WRITE_VALID_PDE(SystemMapPde
, TempPde
);
356 /* The system PDE entry might be the PDE itself, so check for this */
357 if (PointerPde
->u
.Hard
.Valid
== 0)
359 /* It's different, so make the real PDE valid too */
360 MI_WRITE_VALID_PDE(PointerPde
, TempPde
);
364 /* Release the lock and keep going with the next PDE */
365 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
374 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea
,
375 IN BOOLEAN FailIfSystemViews
)
379 /* Flag not yet supported */
380 ASSERT(FailIfSystemViews
== FALSE
);
382 /* Lock the PFN database */
383 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
385 /* State not yet supported */
386 ASSERT(ControlArea
->u
.Flags
.BeingPurged
== 0);
388 /* Increase the reference counts */
389 ControlArea
->NumberOfMappedViews
++;
390 ControlArea
->NumberOfUserReferences
++;
391 ASSERT(ControlArea
->NumberOfSectionReferences
!= 0);
393 /* Release the PFN lock and return success */
394 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
395 return STATUS_SUCCESS
;
400 MiLocateSubsection(IN PMMVAD Vad
,
403 PSUBSECTION Subsection
;
404 PCONTROL_AREA ControlArea
;
407 /* Get the control area */
408 ControlArea
= Vad
->ControlArea
;
409 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
410 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
411 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
413 /* Get the subsection */
414 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
416 /* We only support single-subsection segments */
417 ASSERT(Subsection
->SubsectionBase
!= NULL
);
418 ASSERT(Vad
->FirstPrototypePte
>= Subsection
->SubsectionBase
);
419 ASSERT(Vad
->FirstPrototypePte
< &Subsection
->SubsectionBase
[Subsection
->PtesInSubsection
]);
421 /* Compute the PTE offset */
422 PteOffset
= (ULONG_PTR
)Vpn
- Vad
->StartingVpn
;
423 PteOffset
+= Vad
->FirstPrototypePte
- Subsection
->SubsectionBase
;
425 /* Again, we only support single-subsection segments */
426 ASSERT(PteOffset
< 0xF0000000);
427 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
429 /* Return the subsection */
435 MiSegmentDelete(IN PSEGMENT Segment
)
437 PCONTROL_AREA ControlArea
;
438 SEGMENT_FLAGS SegmentFlags
;
439 PSUBSECTION Subsection
;
440 PMMPTE PointerPte
, LastPte
, PteForProto
;
445 SegmentFlags
= Segment
->SegmentFlags
;
446 ControlArea
= Segment
->ControlArea
;
448 /* Make sure control area is on the right delete path */
449 ASSERT(ControlArea
->u
.Flags
.BeingDeleted
== 1);
450 ASSERT(ControlArea
->WritableUserReferences
== 0);
452 /* These things are not supported yet */
453 ASSERT(ControlArea
->DereferenceList
.Flink
== NULL
);
454 ASSERT(!(ControlArea
->u
.Flags
.Image
) & !(ControlArea
->u
.Flags
.File
));
455 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
456 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
458 /* Get the subsection and PTEs for this segment */
459 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
460 PointerPte
= Subsection
->SubsectionBase
;
461 LastPte
= PointerPte
+ Segment
->NonExtendedPtes
;
463 /* Lock the PFN database */
464 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
466 /* Check if the master PTE is invalid */
467 PteForProto
= MiAddressToPte(PointerPte
);
468 if (!PteForProto
->u
.Hard
.Valid
)
471 MiMakeSystemAddressValidPfn(PointerPte
, OldIrql
);
474 /* Loop all the segment PTEs */
475 while (PointerPte
< LastPte
)
477 /* Check if it's time to switch master PTEs if we passed a PDE boundary */
478 if (!((ULONG_PTR
)PointerPte
& (PD_SIZE
- 1)) &&
479 (PointerPte
!= Subsection
->SubsectionBase
))
481 /* Check if the master PTE is invalid */
482 PteForProto
= MiAddressToPte(PointerPte
);
483 if (!PteForProto
->u
.Hard
.Valid
)
486 MiMakeSystemAddressValidPfn(PointerPte
, OldIrql
);
490 /* This should be a prototype PTE */
491 TempPte
= *PointerPte
;
492 ASSERT(SegmentFlags
.LargePages
== 0);
493 ASSERT(TempPte
.u
.Hard
.Valid
== 0);
494 ASSERT(TempPte
.u
.Soft
.Prototype
== 1);
496 /* Zero the PTE and keep going */
497 PointerPte
->u
.Long
= 0;
501 /* Release the PFN lock */
502 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
504 /* Free the structures */
505 ExFreePool(ControlArea
);
511 MiCheckControlArea(IN PCONTROL_AREA ControlArea
,
514 BOOLEAN DeleteSegment
= FALSE
;
515 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
517 /* Check if this is the last reference or view */
518 if (!(ControlArea
->NumberOfMappedViews
) &&
519 !(ControlArea
->NumberOfSectionReferences
))
521 /* There should be no more user references either */
522 ASSERT(ControlArea
->NumberOfUserReferences
== 0);
524 /* Not yet supported */
525 ASSERT(ControlArea
->FilePointer
== NULL
);
527 /* The control area is being destroyed */
528 ControlArea
->u
.Flags
.BeingDeleted
= TRUE
;
529 DeleteSegment
= TRUE
;
532 /* Release the PFN lock */
533 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
535 /* Delete the segment if needed */
538 /* No more user write references at all */
539 ASSERT(ControlArea
->WritableUserReferences
== 0);
540 MiSegmentDelete(ControlArea
->Segment
);
546 MiRemoveMappedView(IN PEPROCESS CurrentProcess
,
550 PCONTROL_AREA ControlArea
;
552 /* Get the control area */
553 ControlArea
= Vad
->ControlArea
;
555 /* We only support non-extendable, non-image, pagefile-backed regular sections */
556 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
557 ASSERT(Vad
->u2
.VadFlags2
.ExtendableFile
== FALSE
);
559 ASSERT(ControlArea
->FilePointer
== NULL
);
561 /* Delete the actual virtual memory pages */
562 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
563 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
566 /* Release the working set */
567 MiUnlockProcessWorkingSet(CurrentProcess
, PsGetCurrentThread());
569 /* Lock the PFN database */
570 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
572 /* Remove references */
573 ControlArea
->NumberOfMappedViews
--;
574 ControlArea
->NumberOfUserReferences
--;
576 /* Check if it should be destroyed */
577 MiCheckControlArea(ControlArea
, OldIrql
);
582 MiMapViewInSystemSpace(IN PVOID Section
,
583 IN PMMSESSION Session
,
584 OUT PVOID
*MappedBase
,
585 IN OUT PSIZE_T ViewSize
)
588 PCONTROL_AREA ControlArea
;
589 ULONG Buckets
, SectionSize
;
593 /* Only global mappings for now */
594 ASSERT(Session
== &MmSession
);
596 /* Get the control area, check for any flags ARM3 doesn't yet support */
597 ControlArea
= ((PSECTION
)Section
)->Segment
->ControlArea
;
598 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
599 ASSERT(ControlArea
->FilePointer
== NULL
);
600 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
601 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
602 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
604 /* Increase the reference and map count on the control area, no purges yet */
605 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
606 ASSERT(NT_SUCCESS(Status
));
608 /* Get the section size at creation time */
609 SectionSize
= ((PSECTION
)Section
)->SizeOfSection
.LowPart
;
611 /* If the caller didn't specify a view size, assume the whole section */
612 if (!(*ViewSize
)) *ViewSize
= SectionSize
;
614 /* Check if the caller wanted a larger section than the view */
615 if (*ViewSize
> SectionSize
)
617 /* We should probably fail. FIXME TODO */
622 /* Get the number of 64K buckets required for this mapping */
623 Buckets
= *ViewSize
/ MI_SYSTEM_VIEW_BUCKET_SIZE
;
624 if (*ViewSize
& (MI_SYSTEM_VIEW_BUCKET_SIZE
- 1)) Buckets
++;
626 /* Check if the view is more than 4GB large */
627 if (Buckets
>= MI_SYSTEM_VIEW_BUCKET_SIZE
)
629 /* We should probably fail */
634 /* Insert this view into system space and get a base address for it */
635 Base
= MiInsertInSystemSpace(Session
, Buckets
, ControlArea
);
638 #if (_MI_PAGING_LEVELS == 2)
639 /* Create the PDEs needed for this mapping, and double-map them if needed */
640 MiFillSystemPageDirectory(Base
, Buckets
* MI_SYSTEM_VIEW_BUCKET_SIZE
);
643 /* Create the actual prototype PTEs for this mapping */
644 Status
= MiAddMappedPtes(MiAddressToPte(Base
),
645 BYTES_TO_PAGES(*ViewSize
),
647 ASSERT(NT_SUCCESS(Status
));
649 /* Return the base adress of the mapping and success */
651 return STATUS_SUCCESS
;
656 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea
,
657 IN PEPROCESS Process
,
658 IN PVOID
*BaseAddress
,
659 IN PLARGE_INTEGER SectionOffset
,
662 IN SECTION_INHERIT InheritDisposition
,
663 IN ULONG ProtectionMask
,
665 IN ULONG_PTR ZeroBits
,
666 IN ULONG AllocationType
)
669 PETHREAD Thread
= PsGetCurrentThread();
670 ULONG_PTR StartAddress
, EndingAddress
;
671 PSUBSECTION Subsection
;
673 PFN_NUMBER PteOffset
;
676 /* Get the segment and subection for this section */
677 Segment
= ControlArea
->Segment
;
678 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
680 /* Non-pagefile-backed sections not supported */
681 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
682 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
683 ASSERT(ControlArea
->FilePointer
== NULL
);
684 ASSERT(Segment
->SegmentFlags
.TotalNumberOfPtes4132
== 0);
686 /* Based sections not supported */
687 ASSERT(Section
->Address
.StartingVpn
== 0);
689 /* These flags/parameters are not supported */
690 ASSERT((AllocationType
& MEM_DOS_LIM
) == 0);
691 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
692 ASSERT(Process
->VmTopDown
== 0);
693 ASSERT(Section
->u
.Flags
.CopyOnWrite
== FALSE
);
694 ASSERT(ZeroBits
== 0);
696 /* First, increase the map count. No purging is supported yet */
697 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
698 ASSERT(NT_SUCCESS(Status
));
700 /* Check if the caller specified the view size */
703 /* The caller did not, so pick a 64K aligned view size based on the offset */
704 SectionOffset
->LowPart
&= ~(_64K
- 1);
705 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
709 /* A size was specified, align it to a 64K boundary */
710 *ViewSize
+= SectionOffset
->LowPart
& (_64K
- 1);
712 /* Align the offset as well to make this an aligned map */
713 SectionOffset
->LowPart
&= ~((ULONG
)_64K
- 1);
716 /* We must be dealing with a 64KB aligned offset */
717 ASSERT((SectionOffset
->LowPart
& ((ULONG
)_64K
- 1)) == 0);
719 /* It's illegal to try to map more than 2GB */
720 if (*ViewSize
>= 0x80000000) return STATUS_INVALID_VIEW_SIZE
;
722 /* Within this section, figure out which PTEs will describe the view */
723 PteOffset
= SectionOffset
->QuadPart
>> PAGE_SHIFT
;
725 /* The offset must be in this segment's PTE chunk and it must be valid */
726 ASSERT(PteOffset
< Segment
->TotalNumberOfPtes
);
727 ASSERT(((SectionOffset
->QuadPart
+ *ViewSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
) >= PteOffset
);
729 /* In ARM3, only one subsection is used for now. It must contain these PTEs */
730 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
731 ASSERT(Subsection
->SubsectionBase
!= NULL
);
733 /* In ARM3, only MEM_COMMIT is supported for now. The PTEs must've been committed */
734 ASSERT(Segment
->NumberOfCommittedPages
>= Segment
->TotalNumberOfPtes
);
736 /* Did the caller specify an address? */
739 /* Which way should we search? */
740 if (AllocationType
& MEM_TOP_DOWN
)
742 /* No, find an address top-down */
743 Status
= MiFindEmptyAddressRangeDownTree(*ViewSize
,
744 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
,
748 (PMMADDRESS_NODE
*)&Process
->VadFreeHint
);
749 ASSERT(NT_SUCCESS(Status
));
753 /* No, find an address bottom-up */
754 Status
= MiFindEmptyAddressRangeInTree(*ViewSize
,
757 (PMMADDRESS_NODE
*)&Process
->VadFreeHint
,
759 ASSERT(NT_SUCCESS(Status
));
764 /* This (rather easy) code path is not yet implemented */
769 /* Get the ending address, which is the last piece we need for the VAD */
770 EndingAddress
= (StartAddress
+ *ViewSize
- 1) | (PAGE_SIZE
- 1);
772 /* A VAD can now be allocated. Do so and zero it out */
773 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD
), 'ldaV');
775 RtlZeroMemory(Vad
, sizeof(MMVAD
));
777 /* Write all the data required in the VAD for handling a fault */
778 Vad
->StartingVpn
= StartAddress
>> PAGE_SHIFT
;
779 Vad
->EndingVpn
= EndingAddress
>> PAGE_SHIFT
;
780 Vad
->ControlArea
= ControlArea
;
781 Vad
->u
.VadFlags
.Protection
= ProtectionMask
;
782 Vad
->u2
.VadFlags2
.FileOffset
= SectionOffset
->QuadPart
>> 16;
783 Vad
->u2
.VadFlags2
.Inherit
= (InheritDisposition
== ViewShare
);
784 if ((AllocationType
& SEC_NO_CHANGE
) || (Section
->u
.Flags
.NoChange
))
786 /* This isn't really implemented yet, but handle setting the flag */
787 Vad
->u
.VadFlags
.NoChange
= 1;
788 Vad
->u2
.VadFlags2
.SecNoChange
= 1;
791 /* Finally, write down the first and last prototype PTE */
792 Vad
->FirstPrototypePte
= &Subsection
->SubsectionBase
[PteOffset
];
793 PteOffset
+= (Vad
->EndingVpn
- Vad
->StartingVpn
);
794 Vad
->LastContiguousPte
= &Subsection
->SubsectionBase
[PteOffset
];
796 /* Make sure the last PTE is valid and still within the subsection */
797 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
798 ASSERT(Vad
->FirstPrototypePte
<= Vad
->LastContiguousPte
);
800 /* FIXME: Should setup VAD bitmap */
801 Status
= STATUS_SUCCESS
;
803 /* Pretend as if we own the working set */
804 MiLockProcessWorkingSet(Process
, Thread
);
807 MiInsertVad(Vad
, Process
);
809 /* Release the working set */
810 MiUnlockProcessWorkingSet(Process
, Thread
);
812 /* Windows stores this for accounting purposes, do so as well */
813 if (!Segment
->u2
.FirstMappedVa
) Segment
->u2
.FirstMappedVa
= (PVOID
)StartAddress
;
815 /* Finally, let the caller know where, and for what size, the view was mapped */
816 *ViewSize
= (ULONG_PTR
)EndingAddress
- (ULONG_PTR
)StartAddress
+ 1;
817 *BaseAddress
= (PVOID
)StartAddress
;
818 return STATUS_SUCCESS
;
823 MiCreatePagingFileMap(OUT PSEGMENT
*Segment
,
824 IN PSIZE_T MaximumSize
,
825 IN ULONG ProtectionMask
,
826 IN ULONG AllocationAttributes
)
832 PCONTROL_AREA ControlArea
;
834 PSUBSECTION Subsection
;
837 /* No large pages in ARM3 yet */
838 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
840 /* Pagefile-backed sections need a known size */
841 if (!(*MaximumSize
)) return STATUS_INVALID_PARAMETER_4
;
843 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
844 SizeLimit
= MAXULONG_PTR
- sizeof(SEGMENT
);
845 SizeLimit
/= sizeof(MMPTE
);
846 SizeLimit
<<= PAGE_SHIFT
;
848 /* Fail if this size is too big */
849 if (*MaximumSize
> SizeLimit
) return STATUS_SECTION_TOO_BIG
;
851 /* Calculate how many Prototype PTEs will be needed */
852 PteCount
= (*MaximumSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
854 /* For commited memory, we must have a valid protection mask */
855 if (AllocationAttributes
& SEC_COMMIT
) ASSERT(ProtectionMask
!= 0);
857 /* The segment contains all the Prototype PTEs, allocate it in paged pool */
858 NewSegment
= ExAllocatePoolWithTag(PagedPool
,
860 sizeof(MMPTE
) * (PteCount
- 1),
863 *Segment
= NewSegment
;
865 /* Now allocate the control area, which has the subsection structure */
866 ControlArea
= ExAllocatePoolWithTag(NonPagedPool
,
867 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
871 /* And zero it out, filling the basic segmnet pointer and reference fields */
872 RtlZeroMemory(ControlArea
, sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
));
873 ControlArea
->Segment
= NewSegment
;
874 ControlArea
->NumberOfSectionReferences
= 1;
875 ControlArea
->NumberOfUserReferences
= 1;
877 /* Convert allocation attributes to control area flags */
878 if (AllocationAttributes
& SEC_BASED
) ControlArea
->u
.Flags
.Based
= 1;
879 if (AllocationAttributes
& SEC_RESERVE
) ControlArea
->u
.Flags
.Reserve
= 1;
880 if (AllocationAttributes
& SEC_COMMIT
) ControlArea
->u
.Flags
.Commit
= 1;
882 /* The subsection follows, write the mask, PTE count and point back to the CA */
883 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
884 Subsection
->ControlArea
= ControlArea
;
885 Subsection
->PtesInSubsection
= PteCount
;
886 Subsection
->u
.SubsectionFlags
.Protection
= ProtectionMask
;
888 /* Zero out the segment's prototype PTEs, and link it with the control area */
889 PointerPte
= &NewSegment
->ThePtes
[0];
890 RtlZeroMemory(NewSegment
, sizeof(SEGMENT
));
891 NewSegment
->PrototypePte
= PointerPte
;
892 NewSegment
->ControlArea
= ControlArea
;
894 /* Save some extra accounting data for the segment as well */
895 NewSegment
->u1
.CreatingProcess
= PsGetCurrentProcess();
896 NewSegment
->SizeOfSegment
= PteCount
* PAGE_SIZE
;
897 NewSegment
->TotalNumberOfPtes
= PteCount
;
898 NewSegment
->NonExtendedPtes
= PteCount
;
900 /* The subsection's base address is the first Prototype PTE in the segment */
901 Subsection
->SubsectionBase
= PointerPte
;
903 /* Start with an empty PTE, unless this is a commit operation */
905 if (AllocationAttributes
& SEC_COMMIT
)
907 /* In which case, write down the protection mask in the Prototype PTEs */
908 TempPte
.u
.Soft
.Protection
= ProtectionMask
;
910 /* For accounting, also mark these pages as being committed */
911 NewSegment
->NumberOfCommittedPages
= PteCount
;
914 /* The template PTE itself for the segment should also have the mask set */
915 NewSegment
->SegmentPteTemplate
.u
.Soft
.Protection
= ProtectionMask
;
917 /* Write out the prototype PTEs, for now they're simply demand zero */
918 RtlFillMemoryUlong(PointerPte
, PteCount
* sizeof(MMPTE
), TempPte
.u
.Long
);
919 return STATUS_SUCCESS
;
924 MmGetFileObjectForSection(IN PVOID SectionObject
)
926 PSECTION_OBJECT Section
;
927 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
928 ASSERT(SectionObject
!= NULL
);
930 /* Check if it's an ARM3, or ReactOS section */
931 if ((ULONG_PTR
)SectionObject
& 1)
933 /* Return the file pointer stored in the control area */
934 Section
= (PVOID
)((ULONG_PTR
)SectionObject
& ~1);
935 return Section
->Segment
->ControlArea
->FilePointer
;
938 /* Return the file object */
939 return ((PROS_SECTION_OBJECT
)SectionObject
)->FileObject
;
944 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject
,
945 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
947 POBJECT_NAME_INFORMATION ObjectNameInfo
;
951 /* Allocate memory for our structure */
952 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
, 1024, ' mM');
953 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
956 Status
= ObQueryNameString(FileObject
,
960 if (!NT_SUCCESS(Status
))
962 /* Failed, free memory */
963 DPRINT1("Name query failed\n");
964 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
970 *ModuleName
= ObjectNameInfo
;
971 return STATUS_SUCCESS
;
976 MmGetFileNameForSection(IN PVOID Section
,
977 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
979 PFILE_OBJECT FileObject
;
981 /* Make sure it's an image section */
982 if ((ULONG_PTR
)Section
& 1)
984 /* Check ARM3 Section flag */
985 if (((PSECTION
)((ULONG_PTR
)Section
& ~1))->u
.Flags
.Image
== 0)
988 DPRINT1("Not an image section\n");
989 return STATUS_SECTION_NOT_IMAGE
;
992 else if (!(((PROS_SECTION_OBJECT
)Section
)->AllocationAttributes
& SEC_IMAGE
))
995 DPRINT1("Not an image section\n");
996 return STATUS_SECTION_NOT_IMAGE
;
999 /* Get the file object */
1000 FileObject
= MmGetFileObjectForSection(Section
);
1001 return MmGetFileNameForFileObject(FileObject
, ModuleName
);
1006 MmGetFileNameForAddress(IN PVOID Address
,
1007 OUT PUNICODE_STRING ModuleName
)
1010 PMEMORY_AREA MemoryArea
;
1011 POBJECT_NAME_INFORMATION ModuleNameInformation
;
1014 PFILE_OBJECT FileObject
= NULL
;
1016 PCONTROL_AREA ControlArea
;
1018 /* Lock address space */
1019 AddressSpace
= MmGetCurrentAddressSpace();
1020 MmLockAddressSpace(AddressSpace
);
1022 /* Locate the memory area for the process by address */
1023 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
1026 /* Fail, the address does not exist */
1028 DPRINT1("Invalid address\n");
1029 MmUnlockAddressSpace(AddressSpace
);
1030 return STATUS_INVALID_ADDRESS
;
1033 /* Check if it's a section view (RosMm section) or ARM3 section */
1034 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
1036 /* Get the section pointer to the SECTION_OBJECT */
1037 Section
= MemoryArea
->Data
.SectionData
.Section
;
1039 /* Unlock address space */
1040 MmUnlockAddressSpace(AddressSpace
);
1042 /* Get the filename of the section */
1043 Status
= MmGetFileNameForSection(Section
, &ModuleNameInformation
);
1045 else if (MemoryArea
->Type
== MEMORY_AREA_OWNED_BY_ARM3
)
1048 Vad
= MiLocateAddress(Address
);
1049 if (!Vad
) goto InvalidAddress
;
1051 /* Make sure it's not a VM VAD */
1052 if (Vad
->u
.VadFlags
.PrivateMemory
== 1)
1055 DPRINT1("Address is not a section\n");
1056 MmUnlockAddressSpace(AddressSpace
);
1057 return STATUS_SECTION_NOT_IMAGE
;
1060 /* Get the control area */
1061 ControlArea
= Vad
->ControlArea
;
1062 if (!(ControlArea
) || !(ControlArea
->u
.Flags
.Image
)) goto NotSection
;
1064 /* Get the file object */
1065 FileObject
= ControlArea
->FilePointer
;
1066 ASSERT(FileObject
!= NULL
);
1067 ObReferenceObject(FileObject
);
1069 /* Unlock address space */
1070 MmUnlockAddressSpace(AddressSpace
);
1072 /* Get the filename of the file object */
1073 Status
= MmGetFileNameForFileObject(FileObject
, &ModuleNameInformation
);
1075 /* Dereference it */
1076 ObDereferenceObject(FileObject
);
1080 /* Trying to access virtual memory or something */
1081 goto InvalidAddress
;
1084 /* Check if we were able to get the file object name */
1085 if (NT_SUCCESS(Status
))
1087 /* Init modulename */
1088 RtlCreateUnicodeString(ModuleName
,
1089 ModuleNameInformation
->Name
.Buffer
);
1091 /* Free temp taged buffer from MmGetFileNameForFileObject() */
1092 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
1093 DPRINT("Found ModuleName %S by address %p\n", ModuleName
->Buffer
, Address
);
1100 /* PUBLIC FUNCTIONS ***********************************************************/
1107 MmCreateArm3Section(OUT PVOID
*SectionObject
,
1108 IN ACCESS_MASK DesiredAccess
,
1109 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1110 IN PLARGE_INTEGER InputMaximumSize
,
1111 IN ULONG SectionPageProtection
,
1112 IN ULONG AllocationAttributes
,
1113 IN HANDLE FileHandle OPTIONAL
,
1114 IN PFILE_OBJECT FileObject OPTIONAL
)
1117 PSECTION NewSection
;
1118 PSUBSECTION Subsection
;
1119 PSEGMENT NewSegment
;
1121 PCONTROL_AREA ControlArea
;
1122 ULONG ProtectionMask
;
1124 /* ARM3 does not yet support this */
1125 ASSERT(FileHandle
== NULL
);
1126 ASSERT(FileObject
== NULL
);
1127 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
1128 ASSERT((AllocationAttributes
& SEC_BASED
) == 0);
1130 /* Make the same sanity checks that the Nt interface should've validated */
1131 ASSERT((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
1132 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
1133 SEC_NO_CHANGE
)) == 0);
1134 ASSERT((AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)) != 0);
1135 ASSERT(!((AllocationAttributes
& SEC_IMAGE
) &&
1136 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
|
1137 SEC_NOCACHE
| SEC_NO_CHANGE
))));
1138 ASSERT(!((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
)));
1139 ASSERT(!((SectionPageProtection
& PAGE_NOCACHE
) ||
1140 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
1141 (SectionPageProtection
& PAGE_GUARD
) ||
1142 (SectionPageProtection
& PAGE_NOACCESS
)));
1144 /* Convert section flag to page flag */
1145 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
1147 /* Check to make sure the protection is correct. Nt* does this already */
1148 ProtectionMask
= MiMakeProtectionMask(SectionPageProtection
);
1149 if (ProtectionMask
== MM_INVALID_PROTECTION
) return STATUS_INVALID_PAGE_PROTECTION
;
1151 /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
1152 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
1154 /* So this must be a pagefile-backed section, create the mappings needed */
1155 Status
= MiCreatePagingFileMap(&NewSegment
,
1156 (PSIZE_T
)InputMaximumSize
,
1158 AllocationAttributes
);
1159 ASSERT(NT_SUCCESS(Status
));
1161 /* Set the initial section object data */
1162 Section
.InitialPageProtection
= SectionPageProtection
;
1163 Section
.Segment
= NULL
;
1164 Section
.SizeOfSection
.QuadPart
= NewSegment
->SizeOfSegment
;
1165 Section
.Segment
= NewSegment
;
1167 /* THe mapping created a control area and segment, save the flags */
1168 ControlArea
= NewSegment
->ControlArea
;
1169 Section
.u
.LongFlags
= ControlArea
->u
.LongFlags
;
1171 /* ARM3 cannot support these right now, make sure they're not being set */
1172 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
1173 ASSERT(ControlArea
->FilePointer
== NULL
);
1174 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
1175 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
1176 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
1178 /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
1179 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
1180 ASSERT(Subsection
->NextSubsection
== NULL
);
1182 /* Create the actual section object, with enough space for the prototype PTEs */
1183 Status
= ObCreateObject(ExGetPreviousMode(),
1184 MmSectionObjectType
,
1186 ExGetPreviousMode(),
1190 NewSegment
->TotalNumberOfPtes
* sizeof(MMPTE
),
1191 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
1192 (PVOID
*)&NewSection
);
1193 ASSERT(NT_SUCCESS(Status
));
1195 /* Now copy the local section object from the stack into this new object */
1196 RtlCopyMemory(NewSection
, &Section
, sizeof(SECTION
));
1197 NewSection
->Address
.StartingVpn
= 0;
1199 /* Return the object and the creation status */
1200 *SectionObject
= (PVOID
)NewSection
;
1209 MmMapViewOfArm3Section(IN PVOID SectionObject
,
1210 IN PEPROCESS Process
,
1211 IN OUT PVOID
*BaseAddress
,
1212 IN ULONG_PTR ZeroBits
,
1213 IN SIZE_T CommitSize
,
1214 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1215 IN OUT PSIZE_T ViewSize
,
1216 IN SECTION_INHERIT InheritDisposition
,
1217 IN ULONG AllocationType
,
1220 KAPC_STATE ApcState
;
1221 BOOLEAN Attached
= FALSE
;
1223 PCONTROL_AREA ControlArea
;
1224 ULONG ProtectionMask
;
1228 /* Get the segment and control area */
1229 Section
= (PSECTION
)SectionObject
;
1230 ControlArea
= Section
->Segment
->ControlArea
;
1232 /* These flags/states are not yet supported by ARM3 */
1233 ASSERT(Section
->u
.Flags
.Image
== 0);
1234 ASSERT(Section
->u
.Flags
.NoCache
== 0);
1235 ASSERT(Section
->u
.Flags
.WriteCombined
== 0);
1236 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
1237 ASSERT(ControlArea
->u
.Flags
.PhysicalMemory
== 0);
1241 /* FIXME: Check if the mapping protection is compatible with the create */
1242 if (!MiIsProtectionCompatible(Section
->InitialPageProtection
, Protect
))
1244 DPRINT1("Mapping protection is incompatible\n");
1245 return STATUS_SECTION_PROTECTION
;
1249 /* Check if the offset and size would cause an overflow */
1250 if ((SectionOffset
->QuadPart
+ *ViewSize
) < SectionOffset
->QuadPart
)
1252 DPRINT1("Section offset overflows\n");
1253 return STATUS_INVALID_VIEW_SIZE
;
1256 /* Check if the offset and size are bigger than the section itself */
1257 if ((SectionOffset
->QuadPart
+ *ViewSize
) > Section
->SizeOfSection
.QuadPart
)
1259 DPRINT1("Section offset is larger than section\n");
1260 return STATUS_INVALID_VIEW_SIZE
;
1263 /* Check if the caller did not specify a view size */
1266 /* Compute it for the caller */
1267 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
1269 /* Check if it's larger than 4GB or overflows into kernel-mode */
1270 if ((*ViewSize
> 0xFFFFFFFF) ||
1271 (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)*BaseAddress
) < *ViewSize
))
1273 DPRINT1("Section view won't fit\n");
1274 return STATUS_INVALID_VIEW_SIZE
;
1278 /* Check if the commit size is larger than the view size */
1279 if (CommitSize
> *ViewSize
)
1281 DPRINT1("Attempting to commit more than the view itself\n");
1282 return STATUS_INVALID_PARAMETER_5
;
1285 /* Check if the view size is larger than the section */
1286 if (*ViewSize
> Section
->SizeOfSection
.QuadPart
)
1288 DPRINT1("The view is larger than the section\n");
1289 return STATUS_INVALID_VIEW_SIZE
;
1292 /* Compute and validate the protection mask */
1293 ProtectionMask
= MiMakeProtectionMask(Protect
);
1294 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1296 DPRINT1("The protection is invalid\n");
1297 return STATUS_INVALID_PAGE_PROTECTION
;
1300 /* We only handle pagefile-backed sections, which cannot be writecombined */
1301 if (Protect
& PAGE_WRITECOMBINE
)
1303 DPRINT1("Cannot write combine a pagefile-backed section\n");
1304 return STATUS_INVALID_PARAMETER_10
;
1307 /* Start by attaching to the current process if needed */
1308 if (PsGetCurrentProcess() != Process
)
1310 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1314 /* Lock the address space and make sure the process is alive */
1315 MmLockAddressSpace(&Process
->Vm
);
1316 if (!Process
->VmDeleted
)
1318 /* Do the actual mapping */
1319 Status
= MiMapViewOfDataSection(ControlArea
,
1333 /* The process is being terminated, fail */
1334 DPRINT1("The process is dying\n");
1335 Status
= STATUS_PROCESS_IS_TERMINATING
;
1338 /* Unlock the address space and detatch if needed, then return status */
1339 MmUnlockAddressSpace(&Process
->Vm
);
1340 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1344 /* SYSTEM CALLS ***************************************************************/
1348 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
1349 IN PVOID File2MappedAsFile
)
1352 return STATUS_NOT_IMPLEMENTED
;
1360 NtCreateSection(OUT PHANDLE SectionHandle
,
1361 IN ACCESS_MASK DesiredAccess
,
1362 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1363 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
1364 IN ULONG SectionPageProtection OPTIONAL
,
1365 IN ULONG AllocationAttributes
,
1366 IN HANDLE FileHandle OPTIONAL
)
1368 LARGE_INTEGER SafeMaximumSize
;
1369 PVOID SectionObject
;
1371 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1375 /* Check for non-existing flags */
1376 if ((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
1377 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
1380 if (!(AllocationAttributes
& 1))
1382 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes
);
1383 return STATUS_INVALID_PARAMETER_6
;
1387 /* Check for no allocation type */
1388 if (!(AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)))
1390 DPRINT1("Missing allocation type in allocation attributes\n");
1391 return STATUS_INVALID_PARAMETER_6
;
1394 /* Check for image allocation with invalid attributes */
1395 if ((AllocationAttributes
& SEC_IMAGE
) &&
1396 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_LARGE_PAGES
|
1397 SEC_NOCACHE
| SEC_NO_CHANGE
)))
1399 DPRINT1("Image allocation with invalid attributes\n");
1400 return STATUS_INVALID_PARAMETER_6
;
1403 /* Check for allocation type is both commit and reserve */
1404 if ((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
))
1406 DPRINT1("Commit and reserve in the same time\n");
1407 return STATUS_INVALID_PARAMETER_6
;
1410 /* Now check for valid protection */
1411 if ((SectionPageProtection
& PAGE_NOCACHE
) ||
1412 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
1413 (SectionPageProtection
& PAGE_GUARD
) ||
1414 (SectionPageProtection
& PAGE_NOACCESS
))
1416 DPRINT1("Sections don't support these protections\n");
1417 return STATUS_INVALID_PAGE_PROTECTION
;
1420 /* Use a maximum size of zero, if none was specified */
1421 SafeMaximumSize
.QuadPart
= 0;
1423 /* Check for user-mode caller */
1424 if (PreviousMode
!= KernelMode
)
1429 /* Safely check user-mode parameters */
1430 if (MaximumSize
) SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
1431 MaximumSize
= &SafeMaximumSize
;
1432 ProbeForWriteHandle(SectionHandle
);
1434 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1436 /* Return the exception code */
1437 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1441 else if (!MaximumSize
) MaximumSize
= &SafeMaximumSize
;
1443 /* Check that MaximumSize is valid if backed by paging file */
1444 if ((!FileHandle
) && (!MaximumSize
->QuadPart
))
1445 return STATUS_INVALID_PARAMETER_4
;
1447 /* Create the section */
1448 Status
= MmCreateSection(&SectionObject
,
1452 SectionPageProtection
,
1453 AllocationAttributes
,
1456 if (!NT_SUCCESS(Status
)) return Status
;
1458 /* FIXME: Should zero last page for a file mapping */
1460 /* Now insert the object */
1461 Status
= ObInsertObject(SectionObject
,
1467 if (NT_SUCCESS(Status
))
1472 /* Return the handle safely */
1473 *SectionHandle
= Handle
;
1475 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1482 /* Return the status */
1488 NtOpenSection(OUT PHANDLE SectionHandle
,
1489 IN ACCESS_MASK DesiredAccess
,
1490 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1494 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1497 /* Check for user-mode caller */
1498 if (PreviousMode
!= KernelMode
)
1503 /* Safely check user-mode parameters */
1504 ProbeForWriteHandle(SectionHandle
);
1506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1508 /* Return the exception code */
1509 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1514 /* Try opening the object */
1515 Status
= ObOpenObjectByName(ObjectAttributes
,
1516 MmSectionObjectType
,
1526 /* Return the handle safely */
1527 *SectionHandle
= Handle
;
1529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1535 /* Return the status */
1541 NtMapViewOfSection(IN HANDLE SectionHandle
,
1542 IN HANDLE ProcessHandle
,
1543 IN OUT PVOID
* BaseAddress
,
1544 IN ULONG_PTR ZeroBits
,
1545 IN SIZE_T CommitSize
,
1546 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1547 IN OUT PSIZE_T ViewSize
,
1548 IN SECTION_INHERIT InheritDisposition
,
1549 IN ULONG AllocationType
,
1552 PVOID SafeBaseAddress
;
1553 LARGE_INTEGER SafeSectionOffset
;
1554 SIZE_T SafeViewSize
;
1555 PROS_SECTION_OBJECT Section
;
1558 ACCESS_MASK DesiredAccess
;
1559 ULONG ProtectionMask
;
1560 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1562 /* Check for invalid zero bits */
1563 if (ZeroBits
> 21) // per-arch?
1565 DPRINT1("Invalid zero bits\n");
1566 return STATUS_INVALID_PARAMETER_4
;
1569 /* Check for invalid inherit disposition */
1570 if ((InheritDisposition
> ViewUnmap
) || (InheritDisposition
< ViewShare
))
1572 DPRINT1("Invalid inherit disposition\n");
1573 return STATUS_INVALID_PARAMETER_8
;
1576 /* Allow only valid allocation types */
1577 if ((AllocationType
& ~(MEM_TOP_DOWN
| MEM_LARGE_PAGES
| MEM_DOS_LIM
|
1578 SEC_NO_CHANGE
| MEM_RESERVE
)))
1580 DPRINT1("Invalid allocation type\n");
1581 return STATUS_INVALID_PARAMETER_9
;
1584 /* Convert the protection mask, and validate it */
1585 ProtectionMask
= MiMakeProtectionMask(Protect
);
1586 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1588 DPRINT1("Invalid page protection\n");
1589 return STATUS_INVALID_PAGE_PROTECTION
;
1592 /* Now convert the protection mask into desired section access mask */
1593 DesiredAccess
= MmMakeSectionAccess
[ProtectionMask
& 0x7];
1595 /* Assume no section offset */
1596 SafeSectionOffset
.QuadPart
= 0;
1601 /* Check for unsafe parameters */
1602 if (PreviousMode
!= KernelMode
)
1604 /* Probe the parameters */
1605 ProbeForWritePointer(BaseAddress
);
1606 ProbeForWriteSize_t(ViewSize
);
1609 /* Check if a section offset was given */
1612 /* Check for unsafe parameters and capture section offset */
1613 if (PreviousMode
!= KernelMode
) ProbeForWriteLargeInteger(SectionOffset
);
1614 SafeSectionOffset
= *SectionOffset
;
1617 /* Capture the other parameters */
1618 SafeBaseAddress
= *BaseAddress
;
1619 SafeViewSize
= *ViewSize
;
1621 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1623 /* Return the exception code */
1624 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1628 /* Check for kernel-mode address */
1629 if (SafeBaseAddress
> MM_HIGHEST_VAD_ADDRESS
)
1631 DPRINT1("Kernel base not allowed\n");
1632 return STATUS_INVALID_PARAMETER_3
;
1635 /* Check for range entering kernel-mode */
1636 if (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)SafeBaseAddress
) < SafeViewSize
)
1638 DPRINT1("Overflowing into kernel base not allowed\n");
1639 return STATUS_INVALID_PARAMETER_3
;
1642 /* Check for invalid zero bits */
1643 if (((ULONG_PTR
)SafeBaseAddress
+ SafeViewSize
) > (0xFFFFFFFF >> ZeroBits
)) // arch?
1645 DPRINT1("Invalid zero bits\n");
1646 return STATUS_INVALID_PARAMETER_4
;
1649 /* Reference the process */
1650 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1651 PROCESS_VM_OPERATION
,
1656 if (!NT_SUCCESS(Status
)) return Status
;
1658 /* Reference the section */
1659 Status
= ObReferenceObjectByHandle(SectionHandle
,
1661 MmSectionObjectType
,
1665 if (!NT_SUCCESS(Status
))
1667 ObDereferenceObject(Process
);
1671 /* Now do the actual mapping */
1672 Status
= MmMapViewOfSection(Section
,
1683 /* Check if this is an image for the current process */
1684 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
1685 (Process
== PsGetCurrentProcess()) &&
1686 ((Status
!= STATUS_IMAGE_NOT_AT_BASE
) ||
1687 (Status
!= STATUS_CONFLICTING_ADDRESSES
)))
1689 /* Notify the debugger */
1690 DbgkMapViewOfSection(Section
,
1692 SafeSectionOffset
.LowPart
,
1696 /* Return data only on success */
1697 if (NT_SUCCESS(Status
))
1702 /* Return parameters to user */
1703 *BaseAddress
= SafeBaseAddress
;
1704 *ViewSize
= SafeViewSize
;
1705 if (SectionOffset
) *SectionOffset
= SafeSectionOffset
;
1707 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1714 /* Dereference all objects and return status */
1715 ObDereferenceObject(Section
);
1716 ObDereferenceObject(Process
);
1722 NtUnmapViewOfSection(IN HANDLE ProcessHandle
,
1723 IN PVOID BaseAddress
)
1727 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1729 /* Don't allowing mapping kernel views */
1730 if ((PreviousMode
== UserMode
) && (BaseAddress
> MM_HIGHEST_USER_ADDRESS
))
1732 DPRINT1("Trying to unmap a kernel view\n");
1733 return STATUS_NOT_MAPPED_VIEW
;
1736 /* Reference the process */
1737 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1738 PROCESS_VM_OPERATION
,
1743 if (!NT_SUCCESS(Status
)) return Status
;
1745 /* Unmap the view */
1746 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
1748 /* Dereference the process and return status */
1749 ObDereferenceObject(Process
);
1755 NtExtendSection(IN HANDLE SectionHandle
,
1756 IN OUT PLARGE_INTEGER NewMaximumSize
)
1758 LARGE_INTEGER SafeNewMaximumSize
;
1759 PROS_SECTION_OBJECT Section
;
1761 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1763 /* Check for user-mode parameters */
1764 if (PreviousMode
!= KernelMode
)
1769 /* Probe and capture the maximum size, it's both read and write */
1770 ProbeForWriteLargeInteger(NewMaximumSize
);
1771 SafeNewMaximumSize
= *NewMaximumSize
;
1773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1775 /* Return the exception code */
1776 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1782 /* Just read the size directly */
1783 SafeNewMaximumSize
= *NewMaximumSize
;
1786 /* Reference the section */
1787 Status
= ObReferenceObjectByHandle(SectionHandle
,
1788 SECTION_EXTEND_SIZE
,
1789 MmSectionObjectType
,
1793 if (!NT_SUCCESS(Status
)) return Status
;
1795 /* Really this should go in MmExtendSection */
1796 if (!(Section
->AllocationAttributes
& SEC_FILE
))
1798 DPRINT1("Not extending a file\n");
1799 ObDereferenceObject(Section
);
1800 return STATUS_SECTION_NOT_EXTENDED
;
1803 /* FIXME: Do the work */
1805 /* Dereference the section */
1806 ObDereferenceObject(Section
);
1811 /* Write back the new size */
1812 *NewMaximumSize
= SafeNewMaximumSize
;
1814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1820 /* Return the status */
1821 return STATUS_NOT_IMPLEMENTED
;
1824 /* PUBLIC FUNCTIONS ***********************************************************/
1831 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1842 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
1843 IN BOOLEAN DelayClose
)
1854 MmMapViewInSessionSpace(IN PVOID Section
,
1855 OUT PVOID
*MappedBase
,
1856 IN OUT PSIZE_T ViewSize
)
1859 return STATUS_NOT_IMPLEMENTED
;
1867 MmUnmapViewInSessionSpace(IN PVOID MappedBase
)
1870 return STATUS_NOT_IMPLEMENTED
;