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 PageFrameIndex
= MiRemoveZeroPage(MI_GET_NEXT_COLOR());
343 ASSERT(PageFrameIndex
);
344 TempPde
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
346 /* Initialize its PFN entry, with the parent system page directory page table */
347 MiInitializePfnForOtherProcess(PageFrameIndex
,
349 MmSystemPageDirectory
[(PointerPde
- MiAddressToPde(NULL
)) / PDE_COUNT
]);
351 /* Make the system PDE entry valid */
352 MI_WRITE_VALID_PTE(SystemMapPde
, TempPde
);
354 /* The system PDE entry might be the PDE itself, so check for this */
355 if (PointerPde
->u
.Hard
.Valid
== 0)
357 /* It's different, so make the real PDE valid too */
358 MI_WRITE_VALID_PTE(PointerPde
, TempPde
);
362 /* Release the lock and keep going with the next PDE */
363 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
372 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea
,
373 IN BOOLEAN FailIfSystemViews
)
377 /* Flag not yet supported */
378 ASSERT(FailIfSystemViews
== FALSE
);
380 /* Lock the PFN database */
381 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
383 /* State not yet supported */
384 ASSERT(ControlArea
->u
.Flags
.BeingPurged
== 0);
386 /* Increase the reference counts */
387 ControlArea
->NumberOfMappedViews
++;
388 ControlArea
->NumberOfUserReferences
++;
389 ASSERT(ControlArea
->NumberOfSectionReferences
!= 0);
391 /* Release the PFN lock and return success */
392 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
393 return STATUS_SUCCESS
;
398 MiLocateSubsection(IN PMMVAD Vad
,
401 PSUBSECTION Subsection
;
402 PCONTROL_AREA ControlArea
;
405 /* Get the control area */
406 ControlArea
= Vad
->ControlArea
;
407 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
408 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
409 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
411 /* Get the subsection */
412 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
414 /* We only support single-subsection segments */
415 ASSERT(Subsection
->SubsectionBase
!= NULL
);
416 ASSERT(Vad
->FirstPrototypePte
>= Subsection
->SubsectionBase
);
417 ASSERT(Vad
->FirstPrototypePte
< &Subsection
->SubsectionBase
[Subsection
->PtesInSubsection
]);
419 /* Compute the PTE offset */
420 PteOffset
= (ULONG_PTR
)Vpn
- Vad
->StartingVpn
;
421 PteOffset
+= Vad
->FirstPrototypePte
- Subsection
->SubsectionBase
;
423 /* Again, we only support single-subsection segments */
424 ASSERT(PteOffset
< 0xF0000000);
425 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
427 /* Return the subsection */
433 MiSegmentDelete(IN PSEGMENT Segment
)
435 PCONTROL_AREA ControlArea
;
436 SEGMENT_FLAGS SegmentFlags
;
437 PSUBSECTION Subsection
;
438 PMMPTE PointerPte
, LastPte
, PteForProto
;
443 SegmentFlags
= Segment
->SegmentFlags
;
444 ControlArea
= Segment
->ControlArea
;
446 /* Make sure control area is on the right delete path */
447 ASSERT(ControlArea
->u
.Flags
.BeingDeleted
== 1);
448 ASSERT(ControlArea
->WritableUserReferences
== 0);
450 /* These things are not supported yet */
451 ASSERT(ControlArea
->DereferenceList
.Flink
== NULL
);
452 ASSERT(!(ControlArea
->u
.Flags
.Image
) & !(ControlArea
->u
.Flags
.File
));
453 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
454 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
456 /* Get the subsection and PTEs for this segment */
457 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
458 PointerPte
= Subsection
->SubsectionBase
;
459 LastPte
= PointerPte
+ Segment
->NonExtendedPtes
;
461 /* Lock the PFN database */
462 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
464 /* Check if the master PTE is invalid */
465 PteForProto
= MiAddressToPte(PointerPte
);
466 if (!PteForProto
->u
.Hard
.Valid
)
469 MiMakeSystemAddressValidPfn(PointerPte
, OldIrql
);
472 /* Loop all the segment PTEs */
473 while (PointerPte
< LastPte
)
475 /* Check if it's time to switch master PTEs if we passed a PDE boundary */
476 if (!((ULONG_PTR
)PointerPte
& (PD_SIZE
- 1)) &&
477 (PointerPte
!= Subsection
->SubsectionBase
))
479 /* Check if the master PTE is invalid */
480 PteForProto
= MiAddressToPte(PointerPte
);
481 if (!PteForProto
->u
.Hard
.Valid
)
484 MiMakeSystemAddressValidPfn(PointerPte
, OldIrql
);
488 /* This should be a prototype PTE */
489 TempPte
= *PointerPte
;
490 ASSERT(SegmentFlags
.LargePages
== 0);
491 ASSERT(TempPte
.u
.Hard
.Valid
== 0);
492 ASSERT(TempPte
.u
.Soft
.Prototype
== 1);
494 /* Zero the PTE and keep going */
495 PointerPte
->u
.Long
= 0;
499 /* Release the PFN lock */
500 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
502 /* Free the structures */
503 ExFreePool(ControlArea
);
509 MiCheckControlArea(IN PCONTROL_AREA ControlArea
,
512 BOOLEAN DeleteSegment
= FALSE
;
513 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
515 /* Check if this is the last reference or view */
516 if (!(ControlArea
->NumberOfMappedViews
) &&
517 !(ControlArea
->NumberOfSectionReferences
))
519 /* There should be no more user references either */
520 ASSERT(ControlArea
->NumberOfUserReferences
== 0);
522 /* Not yet supported */
523 ASSERT(ControlArea
->FilePointer
== NULL
);
525 /* The control area is being destroyed */
526 ControlArea
->u
.Flags
.BeingDeleted
= TRUE
;
527 DeleteSegment
= TRUE
;
530 /* Release the PFN lock */
531 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
533 /* Delete the segment if needed */
536 /* No more user write references at all */
537 ASSERT(ControlArea
->WritableUserReferences
== 0);
538 MiSegmentDelete(ControlArea
->Segment
);
544 MiRemoveMappedView(IN PEPROCESS CurrentProcess
,
548 PCONTROL_AREA ControlArea
;
550 /* Get the control area */
551 ControlArea
= Vad
->ControlArea
;
553 /* We only support non-extendable, non-image, pagefile-backed regular sections */
554 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
555 ASSERT(Vad
->u2
.VadFlags2
.ExtendableFile
== FALSE
);
557 ASSERT(ControlArea
->FilePointer
== NULL
);
559 /* Delete the actual virtual memory pages */
560 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
561 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
564 /* Release the working set */
565 MiUnlockProcessWorkingSet(CurrentProcess
, PsGetCurrentThread());
567 /* Lock the PFN database */
568 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
570 /* Remove references */
571 ControlArea
->NumberOfMappedViews
--;
572 ControlArea
->NumberOfUserReferences
--;
574 /* Check if it should be destroyed */
575 MiCheckControlArea(ControlArea
, OldIrql
);
580 MiMapViewInSystemSpace(IN PVOID Section
,
581 IN PMMSESSION Session
,
582 OUT PVOID
*MappedBase
,
583 IN OUT PSIZE_T ViewSize
)
586 PCONTROL_AREA ControlArea
;
587 ULONG Buckets
, SectionSize
;
591 /* Only global mappings for now */
592 ASSERT(Session
== &MmSession
);
594 /* Get the control area, check for any flags ARM3 doesn't yet support */
595 ControlArea
= ((PSECTION
)Section
)->Segment
->ControlArea
;
596 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
597 ASSERT(ControlArea
->FilePointer
== NULL
);
598 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
599 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
600 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
602 /* Increase the reference and map count on the control area, no purges yet */
603 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
604 ASSERT(NT_SUCCESS(Status
));
606 /* Get the section size at creation time */
607 SectionSize
= ((PSECTION
)Section
)->SizeOfSection
.LowPart
;
609 /* If the caller didn't specify a view size, assume the whole section */
610 if (!(*ViewSize
)) *ViewSize
= SectionSize
;
612 /* Check if the caller wanted a larger section than the view */
613 if (*ViewSize
> SectionSize
)
615 /* We should probably fail. FIXME TODO */
620 /* Get the number of 64K buckets required for this mapping */
621 Buckets
= *ViewSize
/ MI_SYSTEM_VIEW_BUCKET_SIZE
;
622 if (*ViewSize
& (MI_SYSTEM_VIEW_BUCKET_SIZE
- 1)) Buckets
++;
624 /* Check if the view is more than 4GB large */
625 if (Buckets
>= MI_SYSTEM_VIEW_BUCKET_SIZE
)
627 /* We should probably fail */
632 /* Insert this view into system space and get a base address for it */
633 Base
= MiInsertInSystemSpace(Session
, Buckets
, ControlArea
);
636 #if (_MI_PAGING_LEVELS == 2)
637 /* Create the PDEs needed for this mapping, and double-map them if needed */
638 MiFillSystemPageDirectory(Base
, Buckets
* MI_SYSTEM_VIEW_BUCKET_SIZE
);
641 /* Create the actual prototype PTEs for this mapping */
642 Status
= MiAddMappedPtes(MiAddressToPte(Base
),
643 BYTES_TO_PAGES(*ViewSize
),
645 ASSERT(NT_SUCCESS(Status
));
647 /* Return the base adress of the mapping and success */
649 return STATUS_SUCCESS
;
654 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea
,
655 IN PEPROCESS Process
,
656 IN PVOID
*BaseAddress
,
657 IN PLARGE_INTEGER SectionOffset
,
660 IN SECTION_INHERIT InheritDisposition
,
661 IN ULONG ProtectionMask
,
663 IN ULONG_PTR ZeroBits
,
664 IN ULONG AllocationType
)
667 PETHREAD Thread
= PsGetCurrentThread();
668 ULONG_PTR StartAddress
, EndingAddress
;
669 PSUBSECTION Subsection
;
671 PFN_NUMBER PteOffset
;
674 /* Get the segment and subection for this section */
675 Segment
= ControlArea
->Segment
;
676 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
678 /* Non-pagefile-backed sections not supported */
679 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
680 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
681 ASSERT(ControlArea
->FilePointer
== NULL
);
682 ASSERT(Segment
->SegmentFlags
.TotalNumberOfPtes4132
== 0);
684 /* Based sections not supported */
685 ASSERT(Section
->Address
.StartingVpn
== 0);
687 /* These flags/parameters are not supported */
688 ASSERT((AllocationType
& MEM_DOS_LIM
) == 0);
689 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
690 ASSERT(Process
->VmTopDown
== 0);
691 ASSERT(Section
->u
.Flags
.CopyOnWrite
== FALSE
);
692 ASSERT(ZeroBits
== 0);
694 /* First, increase the map count. No purging is supported yet */
695 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
696 ASSERT(NT_SUCCESS(Status
));
698 /* Check if the caller specified the view size */
701 /* The caller did not, so pick a 64K aligned view size based on the offset */
702 SectionOffset
->LowPart
&= ~(_64K
- 1);
703 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
707 /* A size was specified, align it to a 64K boundary */
708 *ViewSize
+= SectionOffset
->LowPart
& (_64K
- 1);
710 /* Align the offset as well to make this an aligned map */
711 SectionOffset
->LowPart
&= ~((ULONG
)_64K
- 1);
714 /* We must be dealing with a 64KB aligned offset */
715 ASSERT((SectionOffset
->LowPart
& ((ULONG
)_64K
- 1)) == 0);
717 /* It's illegal to try to map more than 2GB */
718 if (*ViewSize
>= 0x80000000) return STATUS_INVALID_VIEW_SIZE
;
720 /* Within this section, figure out which PTEs will describe the view */
721 PteOffset
= SectionOffset
->QuadPart
>> PAGE_SHIFT
;
723 /* The offset must be in this segment's PTE chunk and it must be valid */
724 ASSERT(PteOffset
< Segment
->TotalNumberOfPtes
);
725 ASSERT(((SectionOffset
->QuadPart
+ *ViewSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
) >= PteOffset
);
727 /* In ARM3, only one subsection is used for now. It must contain these PTEs */
728 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
729 ASSERT(Subsection
->SubsectionBase
!= NULL
);
731 /* In ARM3, only MEM_COMMIT is supported for now. The PTEs must've been committed */
732 ASSERT(Segment
->NumberOfCommittedPages
>= Segment
->TotalNumberOfPtes
);
734 /* Did the caller specify an address? */
737 /* Which way should we search? */
738 if (AllocationType
& MEM_TOP_DOWN
)
740 /* No, find an address top-down */
741 Status
= MiFindEmptyAddressRangeDownTree(*ViewSize
,
742 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
,
746 (PMMADDRESS_NODE
*)&Process
->VadFreeHint
);
747 ASSERT(NT_SUCCESS(Status
));
751 /* No, find an address bottom-up */
752 Status
= MiFindEmptyAddressRangeInTree(*ViewSize
,
755 (PMMADDRESS_NODE
*)&Process
->VadFreeHint
,
757 ASSERT(NT_SUCCESS(Status
));
762 /* This (rather easy) code path is not yet implemented */
767 /* Get the ending address, which is the last piece we need for the VAD */
768 EndingAddress
= (StartAddress
+ *ViewSize
- 1) | (PAGE_SIZE
- 1);
770 /* A VAD can now be allocated. Do so and zero it out */
771 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD
), 'ldaV');
773 RtlZeroMemory(Vad
, sizeof(MMVAD
));
775 /* Write all the data required in the VAD for handling a fault */
776 Vad
->StartingVpn
= StartAddress
>> PAGE_SHIFT
;
777 Vad
->EndingVpn
= EndingAddress
>> PAGE_SHIFT
;
778 Vad
->ControlArea
= ControlArea
;
779 Vad
->u
.VadFlags
.Protection
= ProtectionMask
;
780 Vad
->u2
.VadFlags2
.FileOffset
= SectionOffset
->QuadPart
>> 16;
781 Vad
->u2
.VadFlags2
.Inherit
= (InheritDisposition
== ViewShare
);
782 if ((AllocationType
& SEC_NO_CHANGE
) || (Section
->u
.Flags
.NoChange
))
784 /* This isn't really implemented yet, but handle setting the flag */
785 Vad
->u
.VadFlags
.NoChange
= 1;
786 Vad
->u2
.VadFlags2
.SecNoChange
= 1;
789 /* Finally, write down the first and last prototype PTE */
790 Vad
->FirstPrototypePte
= &Subsection
->SubsectionBase
[PteOffset
];
791 PteOffset
+= (Vad
->EndingVpn
- Vad
->StartingVpn
);
792 Vad
->LastContiguousPte
= &Subsection
->SubsectionBase
[PteOffset
];
794 /* Make sure the last PTE is valid and still within the subsection */
795 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
796 ASSERT(Vad
->FirstPrototypePte
<= Vad
->LastContiguousPte
);
798 /* FIXME: Should setup VAD bitmap */
799 Status
= STATUS_SUCCESS
;
801 /* Pretend as if we own the working set */
802 MiLockProcessWorkingSet(Process
, Thread
);
805 MiInsertVad(Vad
, Process
);
807 /* Release the working set */
808 MiUnlockProcessWorkingSet(Process
, Thread
);
810 /* Windows stores this for accounting purposes, do so as well */
811 if (!Segment
->u2
.FirstMappedVa
) Segment
->u2
.FirstMappedVa
= (PVOID
)StartAddress
;
813 /* Finally, let the caller know where, and for what size, the view was mapped */
814 *ViewSize
= (ULONG_PTR
)EndingAddress
- (ULONG_PTR
)StartAddress
+ 1;
815 *BaseAddress
= (PVOID
)StartAddress
;
816 return STATUS_SUCCESS
;
821 MiCreatePagingFileMap(OUT PSEGMENT
*Segment
,
822 IN PSIZE_T MaximumSize
,
823 IN ULONG ProtectionMask
,
824 IN ULONG AllocationAttributes
)
830 PCONTROL_AREA ControlArea
;
832 PSUBSECTION Subsection
;
835 /* No large pages in ARM3 yet */
836 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
838 /* Pagefile-backed sections need a known size */
839 if (!(*MaximumSize
)) return STATUS_INVALID_PARAMETER_4
;
841 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
842 SizeLimit
= MAXULONG_PTR
- sizeof(SEGMENT
);
843 SizeLimit
/= sizeof(MMPTE
);
844 SizeLimit
<<= PAGE_SHIFT
;
846 /* Fail if this size is too big */
847 if (*MaximumSize
> SizeLimit
) return STATUS_SECTION_TOO_BIG
;
849 /* Calculate how many Prototype PTEs will be needed */
850 PteCount
= (*MaximumSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
852 /* For commited memory, we must have a valid protection mask */
853 if (AllocationAttributes
& SEC_COMMIT
) ASSERT(ProtectionMask
!= 0);
855 /* The segment contains all the Prototype PTEs, allocate it in paged pool */
856 NewSegment
= ExAllocatePoolWithTag(PagedPool
,
858 sizeof(MMPTE
) * (PteCount
- 1),
861 *Segment
= NewSegment
;
863 /* Now allocate the control area, which has the subsection structure */
864 ControlArea
= ExAllocatePoolWithTag(NonPagedPool
,
865 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
869 /* And zero it out, filling the basic segmnet pointer and reference fields */
870 RtlZeroMemory(ControlArea
, sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
));
871 ControlArea
->Segment
= NewSegment
;
872 ControlArea
->NumberOfSectionReferences
= 1;
873 ControlArea
->NumberOfUserReferences
= 1;
875 /* Convert allocation attributes to control area flags */
876 if (AllocationAttributes
& SEC_BASED
) ControlArea
->u
.Flags
.Based
= 1;
877 if (AllocationAttributes
& SEC_RESERVE
) ControlArea
->u
.Flags
.Reserve
= 1;
878 if (AllocationAttributes
& SEC_COMMIT
) ControlArea
->u
.Flags
.Commit
= 1;
880 /* The subsection follows, write the mask, PTE count and point back to the CA */
881 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
882 Subsection
->ControlArea
= ControlArea
;
883 Subsection
->PtesInSubsection
= PteCount
;
884 Subsection
->u
.SubsectionFlags
.Protection
= ProtectionMask
;
886 /* Zero out the segment's prototype PTEs, and link it with the control area */
887 PointerPte
= &NewSegment
->ThePtes
[0];
888 RtlZeroMemory(NewSegment
, sizeof(SEGMENT
));
889 NewSegment
->PrototypePte
= PointerPte
;
890 NewSegment
->ControlArea
= ControlArea
;
892 /* Save some extra accounting data for the segment as well */
893 NewSegment
->u1
.CreatingProcess
= PsGetCurrentProcess();
894 NewSegment
->SizeOfSegment
= PteCount
* PAGE_SIZE
;
895 NewSegment
->TotalNumberOfPtes
= PteCount
;
896 NewSegment
->NonExtendedPtes
= PteCount
;
898 /* The subsection's base address is the first Prototype PTE in the segment */
899 Subsection
->SubsectionBase
= PointerPte
;
901 /* Start with an empty PTE, unless this is a commit operation */
903 if (AllocationAttributes
& SEC_COMMIT
)
905 /* In which case, write down the protection mask in the Prototype PTEs */
906 TempPte
.u
.Soft
.Protection
= ProtectionMask
;
908 /* For accounting, also mark these pages as being committed */
909 NewSegment
->NumberOfCommittedPages
= PteCount
;
912 /* The template PTE itself for the segment should also have the mask set */
913 NewSegment
->SegmentPteTemplate
.u
.Soft
.Protection
= ProtectionMask
;
915 /* Write out the prototype PTEs, for now they're simply demand zero */
916 RtlFillMemoryUlong(PointerPte
, PteCount
* sizeof(MMPTE
), TempPte
.u
.Long
);
917 return STATUS_SUCCESS
;
922 MmGetFileObjectForSection(IN PVOID SectionObject
)
924 PSECTION_OBJECT Section
;
925 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
926 ASSERT(SectionObject
!= NULL
);
928 /* Check if it's an ARM3, or ReactOS section */
929 if ((ULONG_PTR
)SectionObject
& 1)
931 /* Return the file pointer stored in the control area */
932 Section
= (PVOID
)((ULONG_PTR
)SectionObject
& ~1);
933 return Section
->Segment
->ControlArea
->FilePointer
;
936 /* Return the file object */
937 return ((PROS_SECTION_OBJECT
)SectionObject
)->FileObject
;
942 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject
,
943 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
945 POBJECT_NAME_INFORMATION ObjectNameInfo
;
949 /* Allocate memory for our structure */
950 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
, 1024, ' mM');
951 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
954 Status
= ObQueryNameString(FileObject
,
958 if (!NT_SUCCESS(Status
))
960 /* Failed, free memory */
961 DPRINT1("Name query failed\n");
962 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
968 *ModuleName
= ObjectNameInfo
;
969 return STATUS_SUCCESS
;
974 MmGetFileNameForSection(IN PVOID Section
,
975 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
977 PFILE_OBJECT FileObject
;
979 /* Make sure it's an image section */
980 if ((ULONG_PTR
)Section
& 1)
982 /* Check ARM3 Section flag */
983 if (((PSECTION
)((ULONG_PTR
)Section
& ~1))->u
.Flags
.Image
== 0)
986 DPRINT1("Not an image section\n");
987 return STATUS_SECTION_NOT_IMAGE
;
990 else if (!(((PROS_SECTION_OBJECT
)Section
)->AllocationAttributes
& SEC_IMAGE
))
993 DPRINT1("Not an image section\n");
994 return STATUS_SECTION_NOT_IMAGE
;
997 /* Get the file object */
998 FileObject
= MmGetFileObjectForSection(Section
);
999 return MmGetFileNameForFileObject(FileObject
, ModuleName
);
1004 MmGetFileNameForAddress(IN PVOID Address
,
1005 OUT PUNICODE_STRING ModuleName
)
1008 PMEMORY_AREA MemoryArea
;
1009 POBJECT_NAME_INFORMATION ModuleNameInformation
;
1012 PFILE_OBJECT FileObject
= NULL
;
1014 PCONTROL_AREA ControlArea
;
1016 /* Lock address space */
1017 AddressSpace
= MmGetCurrentAddressSpace();
1018 MmLockAddressSpace(AddressSpace
);
1020 /* Locate the memory area for the process by address */
1021 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
1024 /* Fail, the address does not exist */
1026 DPRINT1("Invalid address\n");
1027 MmUnlockAddressSpace(AddressSpace
);
1028 return STATUS_INVALID_ADDRESS
;
1031 /* Check if it's a section view (RosMm section) or ARM3 section */
1032 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
1034 /* Get the section pointer to the SECTION_OBJECT */
1035 Section
= MemoryArea
->Data
.SectionData
.Section
;
1037 /* Unlock address space */
1038 MmUnlockAddressSpace(AddressSpace
);
1040 /* Get the filename of the section */
1041 Status
= MmGetFileNameForSection(Section
, &ModuleNameInformation
);
1043 else if (MemoryArea
->Type
== MEMORY_AREA_OWNED_BY_ARM3
)
1046 Vad
= MiLocateAddress(Address
);
1047 if (!Vad
) goto InvalidAddress
;
1049 /* Make sure it's not a VM VAD */
1050 if (Vad
->u
.VadFlags
.PrivateMemory
== 1)
1053 DPRINT1("Address is not a section\n");
1054 MmUnlockAddressSpace(AddressSpace
);
1055 return STATUS_SECTION_NOT_IMAGE
;
1058 /* Get the control area */
1059 ControlArea
= Vad
->ControlArea
;
1060 if (!(ControlArea
) || !(ControlArea
->u
.Flags
.Image
)) goto NotSection
;
1062 /* Get the file object */
1063 FileObject
= ControlArea
->FilePointer
;
1064 ASSERT(FileObject
!= NULL
);
1065 ObReferenceObject(FileObject
);
1067 /* Unlock address space */
1068 MmUnlockAddressSpace(AddressSpace
);
1070 /* Get the filename of the file object */
1071 Status
= MmGetFileNameForFileObject(FileObject
, &ModuleNameInformation
);
1073 /* Dereference it */
1074 ObDereferenceObject(FileObject
);
1078 /* Trying to access virtual memory or something */
1079 goto InvalidAddress
;
1082 /* Check if we were able to get the file object name */
1083 if (NT_SUCCESS(Status
))
1085 /* Init modulename */
1086 RtlCreateUnicodeString(ModuleName
,
1087 ModuleNameInformation
->Name
.Buffer
);
1089 /* Free temp taged buffer from MmGetFileNameForFileObject() */
1090 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
1091 DPRINT("Found ModuleName %S by address %p\n", ModuleName
->Buffer
, Address
);
1098 /* PUBLIC FUNCTIONS ***********************************************************/
1105 MmCreateArm3Section(OUT PVOID
*SectionObject
,
1106 IN ACCESS_MASK DesiredAccess
,
1107 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1108 IN PLARGE_INTEGER InputMaximumSize
,
1109 IN ULONG SectionPageProtection
,
1110 IN ULONG AllocationAttributes
,
1111 IN HANDLE FileHandle OPTIONAL
,
1112 IN PFILE_OBJECT FileObject OPTIONAL
)
1115 PSECTION NewSection
;
1116 PSUBSECTION Subsection
;
1117 PSEGMENT NewSegment
;
1119 PCONTROL_AREA ControlArea
;
1120 ULONG ProtectionMask
;
1122 /* ARM3 does not yet support this */
1123 ASSERT(FileHandle
== NULL
);
1124 ASSERT(FileObject
== NULL
);
1125 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
1126 ASSERT((AllocationAttributes
& SEC_BASED
) == 0);
1128 /* Make the same sanity checks that the Nt interface should've validated */
1129 ASSERT((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
1130 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
1131 SEC_NO_CHANGE
)) == 0);
1132 ASSERT((AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)) != 0);
1133 ASSERT(!((AllocationAttributes
& SEC_IMAGE
) &&
1134 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
|
1135 SEC_NOCACHE
| SEC_NO_CHANGE
))));
1136 ASSERT(!((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
)));
1137 ASSERT(!((SectionPageProtection
& PAGE_NOCACHE
) ||
1138 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
1139 (SectionPageProtection
& PAGE_GUARD
) ||
1140 (SectionPageProtection
& PAGE_NOACCESS
)));
1142 /* Convert section flag to page flag */
1143 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
1145 /* Check to make sure the protection is correct. Nt* does this already */
1146 ProtectionMask
= MiMakeProtectionMask(SectionPageProtection
);
1147 if (ProtectionMask
== MM_INVALID_PROTECTION
) return STATUS_INVALID_PAGE_PROTECTION
;
1149 /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
1150 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
1152 /* So this must be a pagefile-backed section, create the mappings needed */
1153 Status
= MiCreatePagingFileMap(&NewSegment
,
1154 (PSIZE_T
)InputMaximumSize
,
1156 AllocationAttributes
);
1157 ASSERT(NT_SUCCESS(Status
));
1159 /* Set the initial section object data */
1160 Section
.InitialPageProtection
= SectionPageProtection
;
1161 Section
.Segment
= NULL
;
1162 Section
.SizeOfSection
.QuadPart
= NewSegment
->SizeOfSegment
;
1163 Section
.Segment
= NewSegment
;
1165 /* THe mapping created a control area and segment, save the flags */
1166 ControlArea
= NewSegment
->ControlArea
;
1167 Section
.u
.LongFlags
= ControlArea
->u
.LongFlags
;
1169 /* ARM3 cannot support these right now, make sure they're not being set */
1170 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
1171 ASSERT(ControlArea
->FilePointer
== NULL
);
1172 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
1173 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
1174 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
1176 /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
1177 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
1178 ASSERT(Subsection
->NextSubsection
== NULL
);
1180 /* Create the actual section object, with enough space for the prototype PTEs */
1181 Status
= ObCreateObject(ExGetPreviousMode(),
1182 MmSectionObjectType
,
1184 ExGetPreviousMode(),
1188 NewSegment
->TotalNumberOfPtes
* sizeof(MMPTE
),
1189 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
1190 (PVOID
*)&NewSection
);
1191 ASSERT(NT_SUCCESS(Status
));
1193 /* Now copy the local section object from the stack into this new object */
1194 RtlCopyMemory(NewSection
, &Section
, sizeof(SECTION
));
1195 NewSection
->Address
.StartingVpn
= 0;
1197 /* Return the object and the creation status */
1198 *SectionObject
= (PVOID
)NewSection
;
1207 MmMapViewOfArm3Section(IN PVOID SectionObject
,
1208 IN PEPROCESS Process
,
1209 IN OUT PVOID
*BaseAddress
,
1210 IN ULONG_PTR ZeroBits
,
1211 IN SIZE_T CommitSize
,
1212 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1213 IN OUT PSIZE_T ViewSize
,
1214 IN SECTION_INHERIT InheritDisposition
,
1215 IN ULONG AllocationType
,
1218 KAPC_STATE ApcState
;
1219 BOOLEAN Attached
= FALSE
;
1221 PCONTROL_AREA ControlArea
;
1222 ULONG ProtectionMask
;
1226 /* Get the segment and control area */
1227 Section
= (PSECTION
)SectionObject
;
1228 ControlArea
= Section
->Segment
->ControlArea
;
1230 /* These flags/states are not yet supported by ARM3 */
1231 ASSERT(Section
->u
.Flags
.Image
== 0);
1232 ASSERT(Section
->u
.Flags
.NoCache
== 0);
1233 ASSERT(Section
->u
.Flags
.WriteCombined
== 0);
1234 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
1235 ASSERT(ControlArea
->u
.Flags
.PhysicalMemory
== 0);
1239 /* FIXME: Check if the mapping protection is compatible with the create */
1240 if (!MiIsProtectionCompatible(Section
->InitialPageProtection
, Protect
))
1242 DPRINT1("Mapping protection is incompatible\n");
1243 return STATUS_SECTION_PROTECTION
;
1247 /* Check if the offset and size would cause an overflow */
1248 if ((SectionOffset
->QuadPart
+ *ViewSize
) < SectionOffset
->QuadPart
)
1250 DPRINT1("Section offset overflows\n");
1251 return STATUS_INVALID_VIEW_SIZE
;
1254 /* Check if the offset and size are bigger than the section itself */
1255 if ((SectionOffset
->QuadPart
+ *ViewSize
) > Section
->SizeOfSection
.QuadPart
)
1257 DPRINT1("Section offset is larger than section\n");
1258 return STATUS_INVALID_VIEW_SIZE
;
1261 /* Check if the caller did not specify a view size */
1264 /* Compute it for the caller */
1265 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
1267 /* Check if it's larger than 4GB or overflows into kernel-mode */
1268 if ((*ViewSize
> 0xFFFFFFFF) ||
1269 (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)*BaseAddress
) < *ViewSize
))
1271 DPRINT1("Section view won't fit\n");
1272 return STATUS_INVALID_VIEW_SIZE
;
1276 /* Check if the commit size is larger than the view size */
1277 if (CommitSize
> *ViewSize
)
1279 DPRINT1("Attempting to commit more than the view itself\n");
1280 return STATUS_INVALID_PARAMETER_5
;
1283 /* Check if the view size is larger than the section */
1284 if (*ViewSize
> Section
->SizeOfSection
.QuadPart
)
1286 DPRINT1("The view is larger than the section\n");
1287 return STATUS_INVALID_VIEW_SIZE
;
1290 /* Compute and validate the protection mask */
1291 ProtectionMask
= MiMakeProtectionMask(Protect
);
1292 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1294 DPRINT1("The protection is invalid\n");
1295 return STATUS_INVALID_PAGE_PROTECTION
;
1298 /* We only handle pagefile-backed sections, which cannot be writecombined */
1299 if (Protect
& PAGE_WRITECOMBINE
)
1301 DPRINT1("Cannot write combine a pagefile-backed section\n");
1302 return STATUS_INVALID_PARAMETER_10
;
1305 /* Start by attaching to the current process if needed */
1306 if (PsGetCurrentProcess() != Process
)
1308 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1312 /* Lock the address space and make sure the process is alive */
1313 MmLockAddressSpace(&Process
->Vm
);
1314 if (!Process
->VmDeleted
)
1316 /* Do the actual mapping */
1317 Status
= MiMapViewOfDataSection(ControlArea
,
1331 /* The process is being terminated, fail */
1332 DPRINT1("The process is dying\n");
1333 Status
= STATUS_PROCESS_IS_TERMINATING
;
1336 /* Unlock the address space and detatch if needed, then return status */
1337 MmUnlockAddressSpace(&Process
->Vm
);
1338 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1342 /* SYSTEM CALLS ***************************************************************/
1346 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
1347 IN PVOID File2MappedAsFile
)
1350 return STATUS_NOT_IMPLEMENTED
;
1358 NtCreateSection(OUT PHANDLE SectionHandle
,
1359 IN ACCESS_MASK DesiredAccess
,
1360 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1361 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
1362 IN ULONG SectionPageProtection OPTIONAL
,
1363 IN ULONG AllocationAttributes
,
1364 IN HANDLE FileHandle OPTIONAL
)
1366 LARGE_INTEGER SafeMaximumSize
;
1367 PVOID SectionObject
;
1369 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1373 /* Check for non-existing flags */
1374 if ((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
1375 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
1378 if (!(AllocationAttributes
& 1))
1380 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes
);
1381 return STATUS_INVALID_PARAMETER_6
;
1385 /* Check for no allocation type */
1386 if (!(AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)))
1388 DPRINT1("Missing allocation type in allocation attributes\n");
1389 return STATUS_INVALID_PARAMETER_6
;
1392 /* Check for image allocation with invalid attributes */
1393 if ((AllocationAttributes
& SEC_IMAGE
) &&
1394 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_LARGE_PAGES
|
1395 SEC_NOCACHE
| SEC_NO_CHANGE
)))
1397 DPRINT1("Image allocation with invalid attributes\n");
1398 return STATUS_INVALID_PARAMETER_6
;
1401 /* Check for allocation type is both commit and reserve */
1402 if ((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
))
1404 DPRINT1("Commit and reserve in the same time\n");
1405 return STATUS_INVALID_PARAMETER_6
;
1408 /* Now check for valid protection */
1409 if ((SectionPageProtection
& PAGE_NOCACHE
) ||
1410 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
1411 (SectionPageProtection
& PAGE_GUARD
) ||
1412 (SectionPageProtection
& PAGE_NOACCESS
))
1414 DPRINT1("Sections don't support these protections\n");
1415 return STATUS_INVALID_PAGE_PROTECTION
;
1418 /* Use a maximum size of zero, if none was specified */
1419 SafeMaximumSize
.QuadPart
= 0;
1421 /* Check for user-mode caller */
1422 if (PreviousMode
!= KernelMode
)
1427 /* Safely check user-mode parameters */
1428 if (MaximumSize
) SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
1429 MaximumSize
= &SafeMaximumSize
;
1430 ProbeForWriteHandle(SectionHandle
);
1432 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1434 /* Return the exception code */
1435 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1439 else if (!MaximumSize
) MaximumSize
= &SafeMaximumSize
;
1441 /* Create the section */
1442 Status
= MmCreateSection(&SectionObject
,
1446 SectionPageProtection
,
1447 AllocationAttributes
,
1450 if (!NT_SUCCESS(Status
)) return Status
;
1452 /* FIXME: Should zero last page for a file mapping */
1454 /* Now insert the object */
1455 Status
= ObInsertObject(SectionObject
,
1461 if (NT_SUCCESS(Status
))
1466 /* Return the handle safely */
1467 *SectionHandle
= Handle
;
1469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1476 /* Return the status */
1482 NtOpenSection(OUT PHANDLE SectionHandle
,
1483 IN ACCESS_MASK DesiredAccess
,
1484 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1488 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1491 /* Check for user-mode caller */
1492 if (PreviousMode
!= KernelMode
)
1497 /* Safely check user-mode parameters */
1498 ProbeForWriteHandle(SectionHandle
);
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1502 /* Return the exception code */
1503 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1508 /* Try opening the object */
1509 Status
= ObOpenObjectByName(ObjectAttributes
,
1510 MmSectionObjectType
,
1520 /* Return the handle safely */
1521 *SectionHandle
= Handle
;
1523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1529 /* Return the status */
1535 NtMapViewOfSection(IN HANDLE SectionHandle
,
1536 IN HANDLE ProcessHandle
,
1537 IN OUT PVOID
* BaseAddress
,
1538 IN ULONG_PTR ZeroBits
,
1539 IN SIZE_T CommitSize
,
1540 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1541 IN OUT PSIZE_T ViewSize
,
1542 IN SECTION_INHERIT InheritDisposition
,
1543 IN ULONG AllocationType
,
1546 PVOID SafeBaseAddress
;
1547 LARGE_INTEGER SafeSectionOffset
;
1548 SIZE_T SafeViewSize
;
1549 PROS_SECTION_OBJECT Section
;
1552 ACCESS_MASK DesiredAccess
;
1553 ULONG ProtectionMask
;
1554 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1556 /* Check for invalid zero bits */
1557 if (ZeroBits
> 21) // per-arch?
1559 DPRINT1("Invalid zero bits\n");
1560 return STATUS_INVALID_PARAMETER_4
;
1563 /* Check for invalid inherit disposition */
1564 if ((InheritDisposition
> ViewUnmap
) || (InheritDisposition
< ViewShare
))
1566 DPRINT1("Invalid inherit disposition\n");
1567 return STATUS_INVALID_PARAMETER_8
;
1570 /* Allow only valid allocation types */
1571 if ((AllocationType
& ~(MEM_TOP_DOWN
| MEM_LARGE_PAGES
| MEM_DOS_LIM
|
1572 SEC_NO_CHANGE
| MEM_RESERVE
)))
1574 DPRINT1("Invalid allocation type\n");
1575 return STATUS_INVALID_PARAMETER_9
;
1578 /* Convert the protection mask, and validate it */
1579 ProtectionMask
= MiMakeProtectionMask(Protect
);
1580 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1582 DPRINT1("Invalid page protection\n");
1583 return STATUS_INVALID_PAGE_PROTECTION
;
1586 /* Now convert the protection mask into desired section access mask */
1587 DesiredAccess
= MmMakeSectionAccess
[ProtectionMask
& 0x7];
1589 /* Assume no section offset */
1590 SafeSectionOffset
.QuadPart
= 0;
1595 /* Check for unsafe parameters */
1596 if (PreviousMode
!= KernelMode
)
1598 /* Probe the parameters */
1599 ProbeForWritePointer(BaseAddress
);
1600 ProbeForWriteSize_t(ViewSize
);
1603 /* Check if a section offset was given */
1606 /* Check for unsafe parameters and capture section offset */
1607 if (PreviousMode
!= KernelMode
) ProbeForWriteLargeInteger(SectionOffset
);
1608 SafeSectionOffset
= *SectionOffset
;
1611 /* Capture the other parameters */
1612 SafeBaseAddress
= *BaseAddress
;
1613 SafeViewSize
= *ViewSize
;
1615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1617 /* Return the exception code */
1618 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1622 /* Check for kernel-mode address */
1623 if (SafeBaseAddress
> MM_HIGHEST_VAD_ADDRESS
)
1625 DPRINT1("Kernel base not allowed\n");
1626 return STATUS_INVALID_PARAMETER_3
;
1629 /* Check for range entering kernel-mode */
1630 if (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)SafeBaseAddress
) < SafeViewSize
)
1632 DPRINT1("Overflowing into kernel base not allowed\n");
1633 return STATUS_INVALID_PARAMETER_3
;
1636 /* Check for invalid zero bits */
1637 if (((ULONG_PTR
)SafeBaseAddress
+ SafeViewSize
) > (0xFFFFFFFF >> ZeroBits
)) // arch?
1639 DPRINT1("Invalid zero bits\n");
1640 return STATUS_INVALID_PARAMETER_4
;
1643 /* Reference the process */
1644 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1645 PROCESS_VM_OPERATION
,
1650 if (!NT_SUCCESS(Status
)) return Status
;
1652 /* Reference the section */
1653 Status
= ObReferenceObjectByHandle(SectionHandle
,
1655 MmSectionObjectType
,
1659 if (!NT_SUCCESS(Status
))
1661 ObDereferenceObject(Process
);
1665 /* Now do the actual mapping */
1666 Status
= MmMapViewOfSection(Section
,
1677 /* Check if this is an image for the current process */
1678 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
1679 (Process
== PsGetCurrentProcess()) &&
1680 ((Status
!= STATUS_IMAGE_NOT_AT_BASE
) ||
1681 (Status
!= STATUS_CONFLICTING_ADDRESSES
)))
1683 /* Notify the debugger */
1684 DbgkMapViewOfSection(Section
,
1686 SafeSectionOffset
.LowPart
,
1690 /* Return data only on success */
1691 if (NT_SUCCESS(Status
))
1696 /* Return parameters to user */
1697 *BaseAddress
= SafeBaseAddress
;
1698 *ViewSize
= SafeViewSize
;
1699 if (SectionOffset
) *SectionOffset
= SafeSectionOffset
;
1701 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1708 /* Dereference all objects and return status */
1709 ObDereferenceObject(Section
);
1710 ObDereferenceObject(Process
);
1716 NtUnmapViewOfSection(IN HANDLE ProcessHandle
,
1717 IN PVOID BaseAddress
)
1721 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1723 /* Don't allowing mapping kernel views */
1724 if ((PreviousMode
== UserMode
) && (BaseAddress
> MM_HIGHEST_USER_ADDRESS
))
1726 DPRINT1("Trying to unmap a kernel view\n");
1727 return STATUS_NOT_MAPPED_VIEW
;
1730 /* Reference the process */
1731 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1732 PROCESS_VM_OPERATION
,
1737 if (!NT_SUCCESS(Status
)) return Status
;
1739 /* Unmap the view */
1740 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
1742 /* Dereference the process and return status */
1743 ObDereferenceObject(Process
);
1749 NtExtendSection(IN HANDLE SectionHandle
,
1750 IN OUT PLARGE_INTEGER NewMaximumSize
)
1752 LARGE_INTEGER SafeNewMaximumSize
;
1753 PROS_SECTION_OBJECT Section
;
1755 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1757 /* Check for user-mode parameters */
1758 if (PreviousMode
!= KernelMode
)
1763 /* Probe and capture the maximum size, it's both read and write */
1764 ProbeForWriteLargeInteger(NewMaximumSize
);
1765 SafeNewMaximumSize
= *NewMaximumSize
;
1767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1769 /* Return the exception code */
1770 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1776 /* Just read the size directly */
1777 SafeNewMaximumSize
= *NewMaximumSize
;
1780 /* Reference the section */
1781 Status
= ObReferenceObjectByHandle(SectionHandle
,
1782 SECTION_EXTEND_SIZE
,
1783 MmSectionObjectType
,
1787 if (!NT_SUCCESS(Status
)) return Status
;
1789 /* Really this should go in MmExtendSection */
1790 if (!(Section
->AllocationAttributes
& SEC_FILE
))
1792 DPRINT1("Not extending a file\n");
1793 ObDereferenceObject(Section
);
1794 return STATUS_SECTION_NOT_EXTENDED
;
1797 /* FIXME: Do the work */
1799 /* Dereference the section */
1800 ObDereferenceObject(Section
);
1805 /* Write back the new size */
1806 *NewMaximumSize
= SafeNewMaximumSize
;
1808 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1814 /* Return the status */
1815 return STATUS_NOT_IMPLEMENTED
;
1818 /* PUBLIC FUNCTIONS ***********************************************************/
1825 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1836 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
1837 IN BOOLEAN DelayClose
)
1848 MmMapViewInSessionSpace(IN PVOID Section
,
1849 OUT PVOID
*MappedBase
,
1850 IN OUT PSIZE_T ViewSize
)
1853 return STATUS_NOT_IMPLEMENTED
;
1861 MmUnmapViewInSessionSpace(IN PVOID MappedBase
)
1864 return STATUS_NOT_IMPLEMENTED
;