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 MiMapViewInSystemSpace(IN PVOID Section
,
399 IN PMMSESSION Session
,
400 OUT PVOID
*MappedBase
,
401 IN OUT PSIZE_T ViewSize
)
404 PCONTROL_AREA ControlArea
;
405 ULONG Buckets
, SectionSize
;
409 /* Only global mappings for now */
410 ASSERT(Session
== &MmSession
);
412 /* Get the control area, check for any flags ARM3 doesn't yet support */
413 ControlArea
= ((PSECTION
)Section
)->Segment
->ControlArea
;
414 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
415 ASSERT(ControlArea
->FilePointer
== NULL
);
416 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
417 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
418 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
420 /* Increase the reference and map count on the control area, no purges yet */
421 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
422 ASSERT(NT_SUCCESS(Status
));
424 /* Get the section size at creation time */
425 SectionSize
= ((PSECTION
)Section
)->SizeOfSection
.LowPart
;
427 /* If the caller didn't specify a view size, assume the whole section */
428 if (!(*ViewSize
)) *ViewSize
= SectionSize
;
430 /* Check if the caller wanted a larger section than the view */
431 if (*ViewSize
> SectionSize
)
433 /* We should probably fail. FIXME TODO */
438 /* Get the number of 64K buckets required for this mapping */
439 Buckets
= *ViewSize
/ MI_SYSTEM_VIEW_BUCKET_SIZE
;
440 if (*ViewSize
& (MI_SYSTEM_VIEW_BUCKET_SIZE
- 1)) Buckets
++;
442 /* Check if the view is more than 4GB large */
443 if (Buckets
>= MI_SYSTEM_VIEW_BUCKET_SIZE
)
445 /* We should probably fail */
450 /* Insert this view into system space and get a base address for it */
451 Base
= MiInsertInSystemSpace(Session
, Buckets
, ControlArea
);
454 #if (_MI_PAGING_LEVELS == 2)
455 /* Create the PDEs needed for this mapping, and double-map them if needed */
456 MiFillSystemPageDirectory(Base
, Buckets
* MI_SYSTEM_VIEW_BUCKET_SIZE
);
459 /* Create the actual prototype PTEs for this mapping */
460 Status
= MiAddMappedPtes(MiAddressToPte(Base
),
461 BYTES_TO_PAGES(*ViewSize
),
463 ASSERT(NT_SUCCESS(Status
));
465 /* Return the base adress of the mapping and success */
467 return STATUS_SUCCESS
;
472 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea
,
473 IN PEPROCESS Process
,
474 IN PVOID
*BaseAddress
,
475 IN PLARGE_INTEGER SectionOffset
,
478 IN SECTION_INHERIT InheritDisposition
,
479 IN ULONG ProtectionMask
,
481 IN ULONG_PTR ZeroBits
,
482 IN ULONG AllocationType
)
485 PETHREAD Thread
= PsGetCurrentThread();
486 ULONG_PTR StartAddress
, EndingAddress
;
487 PSUBSECTION Subsection
;
489 PFN_NUMBER PteOffset
;
492 /* Get the segment and subection for this section */
493 Segment
= ControlArea
->Segment
;
494 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
496 /* Non-pagefile-backed sections not supported */
497 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
498 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
499 ASSERT(ControlArea
->FilePointer
== NULL
);
500 ASSERT(Segment
->SegmentFlags
.TotalNumberOfPtes4132
== 0);
502 /* Based sections not supported */
503 ASSERT(Section
->Address
.StartingVpn
== 0);
505 /* These flags/parameters are not supported */
506 ASSERT((AllocationType
& MEM_DOS_LIM
) == 0);
507 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
508 ASSERT((AllocationType
& MEM_TOP_DOWN
) == 0);
509 ASSERT(Process
->VmTopDown
== 0);
510 ASSERT(Section
->u
.Flags
.CopyOnWrite
== FALSE
);
511 ASSERT(ZeroBits
== 0);
513 /* First, increase the map count. No purging is supported yet */
514 Status
= MiCheckPurgeAndUpMapCount(ControlArea
, FALSE
);
515 ASSERT(NT_SUCCESS(Status
));
517 /* Check if the caller specified the view size */
520 /* The caller did not, so pick a 64K aligned view size based on the offset */
521 SectionOffset
->LowPart
&= ~(_64K
- 1);
522 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
526 /* A size was specified, align it to a 64K boundary */
527 *ViewSize
+= SectionOffset
->LowPart
& (_64K
- 1);
529 /* Align the offset as well to make this an aligned map */
530 SectionOffset
->LowPart
&= ~((ULONG
)_64K
- 1);
533 /* We must be dealing with a 64KB aligned offset */
534 ASSERT((SectionOffset
->LowPart
& ((ULONG
)_64K
- 1)) == 0);
536 /* It's illegal to try to map more than 2GB */
537 if (*ViewSize
>= 0x80000000) return STATUS_INVALID_VIEW_SIZE
;
539 /* Within this section, figure out which PTEs will describe the view */
540 PteOffset
= SectionOffset
->QuadPart
>> PAGE_SHIFT
;
542 /* The offset must be in this segment's PTE chunk and it must be valid */
543 ASSERT(PteOffset
< Segment
->TotalNumberOfPtes
);
544 ASSERT(((SectionOffset
->QuadPart
+ *ViewSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
) >= PteOffset
);
546 /* In ARM3, only one subsection is used for now. It must contain these PTEs */
547 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
548 ASSERT(Subsection
->SubsectionBase
!= NULL
);
550 /* In ARM3, only MEM_COMMIT is supported for now. The PTEs must've been committed */
551 ASSERT(Segment
->NumberOfCommittedPages
>= Segment
->TotalNumberOfPtes
);
553 /* Did the caller specify an address? */
556 /* No, find an address bottom-up */
557 Status
= MiFindEmptyAddressRangeInTree(*ViewSize
,
560 (PMMADDRESS_NODE
*)&Process
->VadFreeHint
,
562 ASSERT(NT_SUCCESS(Status
));
566 /* This (rather easy) code path is not yet implemented */
571 /* Get the ending address, which is the last piece we need for the VAD */
572 EndingAddress
= (StartAddress
+ *ViewSize
- 1) | (PAGE_SIZE
- 1);
574 /* A VAD can now be allocated. Do so and zero it out */
575 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD
), 'ldaV');
577 RtlZeroMemory(Vad
, sizeof(MMVAD
));
579 /* Write all the data required in the VAD for handling a fault */
580 Vad
->StartingVpn
= StartAddress
>> PAGE_SHIFT
;
581 Vad
->EndingVpn
= EndingAddress
>> PAGE_SHIFT
;
582 Vad
->ControlArea
= ControlArea
;
583 Vad
->u
.VadFlags
.Protection
= ProtectionMask
;
584 Vad
->u2
.VadFlags2
.FileOffset
= SectionOffset
->QuadPart
>> 16;
585 Vad
->u2
.VadFlags2
.Inherit
= (InheritDisposition
== ViewShare
);
586 if ((AllocationType
& SEC_NO_CHANGE
) || (Section
->u
.Flags
.NoChange
))
588 /* This isn't really implemented yet, but handle setting the flag */
589 Vad
->u
.VadFlags
.NoChange
= 1;
590 Vad
->u2
.VadFlags2
.SecNoChange
= 1;
593 /* Finally, write down the first and last prototype PTE */
594 Vad
->FirstPrototypePte
= &Subsection
->SubsectionBase
[PteOffset
];
595 PteOffset
+= (Vad
->EndingVpn
- Vad
->StartingVpn
);
596 Vad
->LastContiguousPte
= &Subsection
->SubsectionBase
[PteOffset
];
598 /* Make sure the last PTE is valid and still within the subsection */
599 ASSERT(PteOffset
< Subsection
->PtesInSubsection
);
600 ASSERT(Vad
->FirstPrototypePte
<= Vad
->LastContiguousPte
);
602 /* FIXME: Should setup VAD bitmap */
603 Status
= STATUS_SUCCESS
;
605 /* Pretend as if we own the working set */
606 MiLockProcessWorkingSet(Process
, Thread
);
609 MiInsertVad(Vad
, Process
);
611 /* Release the working set */
612 MiUnlockProcessWorkingSet(Process
, Thread
);
614 /* Windows stores this for accounting purposes, do so as well */
615 if (!Segment
->u2
.FirstMappedVa
) Segment
->u2
.FirstMappedVa
= (PVOID
)StartAddress
;
617 /* Finally, let the caller know where, and for what size, the view was mapped */
618 *ViewSize
= (ULONG_PTR
)EndingAddress
- (ULONG_PTR
)StartAddress
+ 1;
619 *BaseAddress
= (PVOID
)StartAddress
;
620 return STATUS_SUCCESS
;
625 MiCreatePagingFileMap(OUT PSEGMENT
*Segment
,
626 IN PSIZE_T MaximumSize
,
627 IN ULONG ProtectionMask
,
628 IN ULONG AllocationAttributes
)
634 PCONTROL_AREA ControlArea
;
636 PSUBSECTION Subsection
;
639 /* No large pages in ARM3 yet */
640 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
642 /* Pagefile-backed sections need a known size */
643 if (!(*MaximumSize
)) return STATUS_INVALID_PARAMETER_4
;
645 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
646 SizeLimit
= MAXULONG_PTR
- sizeof(SEGMENT
);
647 SizeLimit
/= sizeof(MMPTE
);
648 SizeLimit
<<= PAGE_SHIFT
;
650 /* Fail if this size is too big */
651 if (*MaximumSize
> SizeLimit
) return STATUS_SECTION_TOO_BIG
;
653 /* Calculate how many Prototype PTEs will be needed */
654 PteCount
= (*MaximumSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
656 /* For commited memory, we must have a valid protection mask */
657 if (AllocationAttributes
& SEC_COMMIT
) ASSERT(ProtectionMask
!= 0);
659 /* The segment contains all the Prototype PTEs, allocate it in paged pool */
660 NewSegment
= ExAllocatePoolWithTag(PagedPool
,
662 sizeof(MMPTE
) * (PteCount
- 1),
665 *Segment
= NewSegment
;
667 /* Now allocate the control area, which has the subsection structure */
668 ControlArea
= ExAllocatePoolWithTag(NonPagedPool
,
669 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
673 /* And zero it out, filling the basic segmnet pointer and reference fields */
674 RtlZeroMemory(ControlArea
, sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
));
675 ControlArea
->Segment
= NewSegment
;
676 ControlArea
->NumberOfSectionReferences
= 1;
677 ControlArea
->NumberOfUserReferences
= 1;
679 /* Convert allocation attributes to control area flags */
680 if (AllocationAttributes
& SEC_BASED
) ControlArea
->u
.Flags
.Based
= 1;
681 if (AllocationAttributes
& SEC_RESERVE
) ControlArea
->u
.Flags
.Reserve
= 1;
682 if (AllocationAttributes
& SEC_COMMIT
) ControlArea
->u
.Flags
.Commit
= 1;
684 /* The subsection follows, write the mask, PTE count and point back to the CA */
685 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
686 Subsection
->ControlArea
= ControlArea
;
687 Subsection
->PtesInSubsection
= PteCount
;
688 Subsection
->u
.SubsectionFlags
.Protection
= ProtectionMask
;
690 /* Zero out the segment's prototype PTEs, and link it with the control area */
691 PointerPte
= &NewSegment
->ThePtes
[0];
692 RtlZeroMemory(NewSegment
, sizeof(SEGMENT
));
693 NewSegment
->PrototypePte
= PointerPte
;
694 NewSegment
->ControlArea
= ControlArea
;
696 /* Save some extra accounting data for the segment as well */
697 NewSegment
->u1
.CreatingProcess
= PsGetCurrentProcess();
698 NewSegment
->SizeOfSegment
= PteCount
* PAGE_SIZE
;
699 NewSegment
->TotalNumberOfPtes
= PteCount
;
700 NewSegment
->NonExtendedPtes
= PteCount
;
702 /* The subsection's base address is the first Prototype PTE in the segment */
703 Subsection
->SubsectionBase
= PointerPte
;
705 /* Start with an empty PTE, unless this is a commit operation */
707 if (AllocationAttributes
& SEC_COMMIT
)
709 /* In which case, write down the protection mask in the Prototype PTEs */
710 TempPte
.u
.Soft
.Protection
= ProtectionMask
;
712 /* For accounting, also mark these pages as being committed */
713 NewSegment
->NumberOfCommittedPages
= PteCount
;
716 /* The template PTE itself for the segment should also have the mask set */
717 NewSegment
->SegmentPteTemplate
.u
.Soft
.Protection
= ProtectionMask
;
719 /* Write out the prototype PTEs, for now they're simply demand zero */
720 RtlFillMemoryUlong(PointerPte
, PteCount
* sizeof(MMPTE
), TempPte
.u
.Long
);
721 return STATUS_SUCCESS
;
726 MmGetFileObjectForSection(IN PVOID SectionObject
)
728 PSECTION_OBJECT Section
;
729 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
730 ASSERT(SectionObject
!= NULL
);
732 /* Check if it's an ARM3, or ReactOS section */
733 if ((ULONG_PTR
)SectionObject
& 1)
735 /* Return the file pointer stored in the control area */
736 Section
= (PVOID
)((ULONG_PTR
)SectionObject
& ~1);
737 return Section
->Segment
->ControlArea
->FilePointer
;
740 /* Return the file object */
741 return ((PROS_SECTION_OBJECT
)SectionObject
)->FileObject
;
746 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject
,
747 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
749 POBJECT_NAME_INFORMATION ObjectNameInfo
;
753 /* Allocate memory for our structure */
754 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
, 1024, ' mM');
755 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
758 Status
= ObQueryNameString(FileObject
,
762 if (!NT_SUCCESS(Status
))
764 /* Failed, free memory */
765 DPRINT1("Name query failed\n");
766 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
772 *ModuleName
= ObjectNameInfo
;
773 return STATUS_SUCCESS
;
778 MmGetFileNameForSection(IN PVOID Section
,
779 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
781 PFILE_OBJECT FileObject
;
783 /* Make sure it's an image section */
784 if ((ULONG_PTR
)Section
& 1)
786 /* Check ARM3 Section flag */
787 if (((PSECTION
)((ULONG_PTR
)Section
& ~1))->u
.Flags
.Image
== 0)
790 DPRINT1("Not an image section\n");
791 return STATUS_SECTION_NOT_IMAGE
;
794 else if (!(((PROS_SECTION_OBJECT
)Section
)->AllocationAttributes
& SEC_IMAGE
))
797 DPRINT1("Not an image section\n");
798 return STATUS_SECTION_NOT_IMAGE
;
801 /* Get the file object */
802 FileObject
= MmGetFileObjectForSection(Section
);
803 return MmGetFileNameForFileObject(FileObject
, ModuleName
);
808 MmGetFileNameForAddress(IN PVOID Address
,
809 OUT PUNICODE_STRING ModuleName
)
812 PMEMORY_AREA MemoryArea
;
813 POBJECT_NAME_INFORMATION ModuleNameInformation
;
816 PFILE_OBJECT FileObject
= NULL
;
818 PCONTROL_AREA ControlArea
;
820 /* Lock address space */
821 AddressSpace
= MmGetCurrentAddressSpace();
822 MmLockAddressSpace(AddressSpace
);
824 /* Locate the memory area for the process by address */
825 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
828 /* Fail, the address does not exist */
830 DPRINT1("Invalid address\n");
831 MmUnlockAddressSpace(AddressSpace
);
832 return STATUS_INVALID_ADDRESS
;
835 /* Check if it's a section view (RosMm section) or ARM3 section */
836 if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
838 /* Get the section pointer to the SECTION_OBJECT */
839 Section
= MemoryArea
->Data
.SectionData
.Section
;
841 /* Unlock address space */
842 MmUnlockAddressSpace(AddressSpace
);
844 /* Get the filename of the section */
845 Status
= MmGetFileNameForSection(Section
, &ModuleNameInformation
);
847 else if (MemoryArea
->Type
== MEMORY_AREA_OWNED_BY_ARM3
)
850 Vad
= MiLocateAddress(Address
);
851 if (!Vad
) goto InvalidAddress
;
853 /* Make sure it's not a VM VAD */
854 if (Vad
->u
.VadFlags
.PrivateMemory
== 1)
857 DPRINT1("Address is not a section\n");
858 MmUnlockAddressSpace(AddressSpace
);
859 return STATUS_SECTION_NOT_IMAGE
;
862 /* Get the control area */
863 ControlArea
= Vad
->ControlArea
;
864 if (!(ControlArea
) || !(ControlArea
->u
.Flags
.Image
)) goto NotSection
;
866 /* Get the file object */
867 FileObject
= ControlArea
->FilePointer
;
868 ASSERT(FileObject
!= NULL
);
869 ObReferenceObject(FileObject
);
871 /* Unlock address space */
872 MmUnlockAddressSpace(AddressSpace
);
874 /* Get the filename of the file object */
875 Status
= MmGetFileNameForFileObject(FileObject
, &ModuleNameInformation
);
878 ObDereferenceObject(FileObject
);
882 /* Trying to access virtual memory or something */
886 /* Check if we were able to get the file object name */
887 if (NT_SUCCESS(Status
))
889 /* Init modulename */
890 RtlCreateUnicodeString(ModuleName
,
891 ModuleNameInformation
->Name
.Buffer
);
893 /* Free temp taged buffer from MmGetFileNameForFileObject() */
894 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
895 DPRINT("Found ModuleName %S by address %p\n", ModuleName
->Buffer
, Address
);
902 /* PUBLIC FUNCTIONS ***********************************************************/
909 MmCreateArm3Section(OUT PVOID
*SectionObject
,
910 IN ACCESS_MASK DesiredAccess
,
911 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
912 IN PLARGE_INTEGER InputMaximumSize
,
913 IN ULONG SectionPageProtection
,
914 IN ULONG AllocationAttributes
,
915 IN HANDLE FileHandle OPTIONAL
,
916 IN PFILE_OBJECT FileObject OPTIONAL
)
920 PSUBSECTION Subsection
;
923 PCONTROL_AREA ControlArea
;
924 ULONG ProtectionMask
;
926 /* ARM3 does not yet support this */
927 ASSERT(FileHandle
== NULL
);
928 ASSERT(FileObject
== NULL
);
929 ASSERT((AllocationAttributes
& SEC_LARGE_PAGES
) == 0);
930 ASSERT((AllocationAttributes
& SEC_BASED
) == 0);
932 /* Make the same sanity checks that the Nt interface should've validated */
933 ASSERT((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
934 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
935 SEC_NO_CHANGE
)) == 0);
936 ASSERT((AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)) != 0);
937 ASSERT(!((AllocationAttributes
& SEC_IMAGE
) &&
938 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
|
939 SEC_NOCACHE
| SEC_NO_CHANGE
))));
940 ASSERT(!((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
)));
941 ASSERT(!((SectionPageProtection
& PAGE_NOCACHE
) ||
942 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
943 (SectionPageProtection
& PAGE_GUARD
) ||
944 (SectionPageProtection
& PAGE_NOACCESS
)));
946 /* Convert section flag to page flag */
947 if (AllocationAttributes
& SEC_NOCACHE
) SectionPageProtection
|= PAGE_NOCACHE
;
949 /* Check to make sure the protection is correct. Nt* does this already */
950 ProtectionMask
= MiMakeProtectionMask(SectionPageProtection
);
951 if (ProtectionMask
== MM_INVALID_PROTECTION
) return STATUS_INVALID_PAGE_PROTECTION
;
953 /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
954 if (AllocationAttributes
& SEC_IMAGE
) return STATUS_INVALID_FILE_FOR_SECTION
;
956 /* So this must be a pagefile-backed section, create the mappings needed */
957 Status
= MiCreatePagingFileMap(&NewSegment
,
958 (PSIZE_T
)InputMaximumSize
,
960 AllocationAttributes
);
961 ASSERT(NT_SUCCESS(Status
));
963 /* Set the initial section object data */
964 Section
.InitialPageProtection
= SectionPageProtection
;
965 Section
.Segment
= NULL
;
966 Section
.SizeOfSection
.QuadPart
= NewSegment
->SizeOfSegment
;
967 Section
.Segment
= NewSegment
;
969 /* THe mapping created a control area and segment, save the flags */
970 ControlArea
= NewSegment
->ControlArea
;
971 Section
.u
.LongFlags
= ControlArea
->u
.LongFlags
;
973 /* ARM3 cannot support these right now, make sure they're not being set */
974 ASSERT(ControlArea
->u
.Flags
.Image
== 0);
975 ASSERT(ControlArea
->FilePointer
== NULL
);
976 ASSERT(ControlArea
->u
.Flags
.GlobalOnlyPerSession
== 0);
977 ASSERT(ControlArea
->u
.Flags
.Rom
== 0);
978 ASSERT(ControlArea
->u
.Flags
.WasPurged
== 0);
980 /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
981 Subsection
= (PSUBSECTION
)(ControlArea
+ 1);
982 ASSERT(Subsection
->NextSubsection
== NULL
);
984 /* Create the actual section object, with enough space for the prototype PTEs */
985 Status
= ObCreateObject(ExGetPreviousMode(),
992 NewSegment
->TotalNumberOfPtes
* sizeof(MMPTE
),
993 sizeof(CONTROL_AREA
) + sizeof(SUBSECTION
),
994 (PVOID
*)&NewSection
);
995 ASSERT(NT_SUCCESS(Status
));
997 /* Now copy the local section object from the stack into this new object */
998 RtlCopyMemory(NewSection
, &Section
, sizeof(SECTION
));
999 NewSection
->Address
.StartingVpn
= 0;
1001 /* Return the object and the creation status */
1002 *SectionObject
= (PVOID
)NewSection
;
1011 MmMapViewOfArm3Section(IN PVOID SectionObject
,
1012 IN PEPROCESS Process
,
1013 IN OUT PVOID
*BaseAddress
,
1014 IN ULONG_PTR ZeroBits
,
1015 IN SIZE_T CommitSize
,
1016 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1017 IN OUT PSIZE_T ViewSize
,
1018 IN SECTION_INHERIT InheritDisposition
,
1019 IN ULONG AllocationType
,
1022 KAPC_STATE ApcState
;
1023 BOOLEAN Attached
= FALSE
;
1025 PCONTROL_AREA ControlArea
;
1026 ULONG ProtectionMask
;
1030 /* Get the segment and control area */
1031 Section
= (PSECTION
)SectionObject
;
1032 ControlArea
= Section
->Segment
->ControlArea
;
1034 /* These flags/states are not yet supported by ARM3 */
1035 ASSERT(Section
->u
.Flags
.Image
== 0);
1036 ASSERT(Section
->u
.Flags
.NoCache
== 0);
1037 ASSERT(Section
->u
.Flags
.WriteCombined
== 0);
1038 ASSERT((AllocationType
& MEM_RESERVE
) == 0);
1039 ASSERT(ControlArea
->u
.Flags
.PhysicalMemory
== 0);
1043 /* FIXME: Check if the mapping protection is compatible with the create */
1044 if (!MiIsProtectionCompatible(Section
->InitialPageProtection
, Protect
))
1046 DPRINT1("Mapping protection is incompatible\n");
1047 return STATUS_SECTION_PROTECTION
;
1051 /* Check if the offset and size would cause an overflow */
1052 if ((SectionOffset
->QuadPart
+ *ViewSize
) < SectionOffset
->QuadPart
)
1054 DPRINT1("Section offset overflows\n");
1055 return STATUS_INVALID_VIEW_SIZE
;
1058 /* Check if the offset and size are bigger than the section itself */
1059 if ((SectionOffset
->QuadPart
+ *ViewSize
) > Section
->SizeOfSection
.QuadPart
)
1061 DPRINT1("Section offset is larger than section\n");
1062 return STATUS_INVALID_VIEW_SIZE
;
1065 /* Check if the caller did not specify a view size */
1068 /* Compute it for the caller */
1069 *ViewSize
= Section
->SizeOfSection
.QuadPart
- SectionOffset
->QuadPart
;
1071 /* Check if it's larger than 4GB or overflows into kernel-mode */
1072 if ((*ViewSize
> 0xFFFFFFFF) ||
1073 (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)*BaseAddress
) < *ViewSize
))
1075 DPRINT1("Section view won't fit\n");
1076 return STATUS_INVALID_VIEW_SIZE
;
1080 /* Check if the commit size is larger than the view size */
1081 if (CommitSize
> *ViewSize
)
1083 DPRINT1("Attempting to commit more than the view itself\n");
1084 return STATUS_INVALID_PARAMETER_5
;
1087 /* Check if the view size is larger than the section */
1088 if (*ViewSize
> Section
->SizeOfSection
.QuadPart
)
1090 DPRINT1("The view is larger than the section\n");
1091 return STATUS_INVALID_VIEW_SIZE
;
1094 /* Compute and validate the protection mask */
1095 ProtectionMask
= MiMakeProtectionMask(Protect
);
1096 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1098 DPRINT1("The protection is invalid\n");
1099 return STATUS_INVALID_PAGE_PROTECTION
;
1102 /* We only handle pagefile-backed sections, which cannot be writecombined */
1103 if (Protect
& PAGE_WRITECOMBINE
)
1105 DPRINT1("Cannot write combine a pagefile-backed section\n");
1106 return STATUS_INVALID_PARAMETER_10
;
1109 /* Start by attaching to the current process if needed */
1110 if (PsGetCurrentProcess() != Process
)
1112 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1116 /* Lock the address space and make sure the process is alive */
1117 MmLockAddressSpace(&Process
->Vm
);
1118 if (!Process
->VmDeleted
)
1120 /* Do the actual mapping */
1121 Status
= MiMapViewOfDataSection(ControlArea
,
1135 /* The process is being terminated, fail */
1136 DPRINT1("The process is dying\n");
1137 Status
= STATUS_PROCESS_IS_TERMINATING
;
1140 /* Unlock the address space and detatch if needed, then return status */
1141 MmUnlockAddressSpace(&Process
->Vm
);
1142 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1146 /* SYSTEM CALLS ***************************************************************/
1150 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
1151 IN PVOID File2MappedAsFile
)
1154 return STATUS_NOT_IMPLEMENTED
;
1162 NtCreateSection(OUT PHANDLE SectionHandle
,
1163 IN ACCESS_MASK DesiredAccess
,
1164 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
1165 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
1166 IN ULONG SectionPageProtection OPTIONAL
,
1167 IN ULONG AllocationAttributes
,
1168 IN HANDLE FileHandle OPTIONAL
)
1170 LARGE_INTEGER SafeMaximumSize
;
1171 PVOID SectionObject
;
1173 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1177 /* Check for non-existing flags */
1178 if ((AllocationAttributes
& ~(SEC_COMMIT
| SEC_RESERVE
| SEC_BASED
|
1179 SEC_LARGE_PAGES
| SEC_IMAGE
| SEC_NOCACHE
|
1182 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes
);
1183 return STATUS_INVALID_PARAMETER_6
;
1186 /* Check for no allocation type */
1187 if (!(AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_IMAGE
)))
1189 DPRINT1("Missing allocation type in allocation attributes\n");
1190 return STATUS_INVALID_PARAMETER_6
;
1193 /* Check for image allocation with invalid attributes */
1194 if ((AllocationAttributes
& SEC_IMAGE
) &&
1195 (AllocationAttributes
& (SEC_COMMIT
| SEC_RESERVE
| SEC_LARGE_PAGES
|
1196 SEC_NOCACHE
| SEC_NO_CHANGE
)))
1198 DPRINT1("Image allocation with invalid attributes\n");
1199 return STATUS_INVALID_PARAMETER_6
;
1202 /* Check for allocation type is both commit and reserve */
1203 if ((AllocationAttributes
& SEC_COMMIT
) && (AllocationAttributes
& SEC_RESERVE
))
1205 DPRINT1("Commit and reserve in the same time\n");
1206 return STATUS_INVALID_PARAMETER_6
;
1209 /* Now check for valid protection */
1210 if ((SectionPageProtection
& PAGE_NOCACHE
) ||
1211 (SectionPageProtection
& PAGE_WRITECOMBINE
) ||
1212 (SectionPageProtection
& PAGE_GUARD
) ||
1213 (SectionPageProtection
& PAGE_NOACCESS
))
1215 DPRINT1("Sections don't support these protections\n");
1216 return STATUS_INVALID_PAGE_PROTECTION
;
1219 /* Use a maximum size of zero, if none was specified */
1220 SafeMaximumSize
.QuadPart
= 0;
1222 /* Check for user-mode caller */
1223 if (PreviousMode
!= KernelMode
)
1228 /* Safely check user-mode parameters */
1229 if (MaximumSize
) SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
1230 MaximumSize
= &SafeMaximumSize
;
1231 ProbeForWriteHandle(SectionHandle
);
1233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1235 /* Return the exception code */
1236 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1240 else if (!MaximumSize
) MaximumSize
= &SafeMaximumSize
;
1242 /* Create the section */
1243 Status
= MmCreateSection(&SectionObject
,
1247 SectionPageProtection
,
1248 AllocationAttributes
,
1251 if (!NT_SUCCESS(Status
)) return Status
;
1253 /* FIXME: Should zero last page for a file mapping */
1255 /* Now insert the object */
1256 Status
= ObInsertObject(SectionObject
,
1262 if (NT_SUCCESS(Status
))
1267 /* Return the handle safely */
1268 *SectionHandle
= Handle
;
1270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1277 /* Return the status */
1283 NtOpenSection(OUT PHANDLE SectionHandle
,
1284 IN ACCESS_MASK DesiredAccess
,
1285 IN POBJECT_ATTRIBUTES ObjectAttributes
)
1289 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1292 /* Check for user-mode caller */
1293 if (PreviousMode
!= KernelMode
)
1298 /* Safely check user-mode parameters */
1299 ProbeForWriteHandle(SectionHandle
);
1301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1303 /* Return the exception code */
1304 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1309 /* Try opening the object */
1310 Status
= ObOpenObjectByName(ObjectAttributes
,
1311 MmSectionObjectType
,
1321 /* Return the handle safely */
1322 *SectionHandle
= Handle
;
1324 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1330 /* Return the status */
1336 NtMapViewOfSection(IN HANDLE SectionHandle
,
1337 IN HANDLE ProcessHandle
,
1338 IN OUT PVOID
* BaseAddress
,
1339 IN ULONG_PTR ZeroBits
,
1340 IN SIZE_T CommitSize
,
1341 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
1342 IN OUT PSIZE_T ViewSize
,
1343 IN SECTION_INHERIT InheritDisposition
,
1344 IN ULONG AllocationType
,
1347 PVOID SafeBaseAddress
;
1348 LARGE_INTEGER SafeSectionOffset
;
1349 SIZE_T SafeViewSize
;
1350 PROS_SECTION_OBJECT Section
;
1353 ACCESS_MASK DesiredAccess
;
1354 ULONG ProtectionMask
;
1355 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1357 /* Check for invalid zero bits */
1358 if (ZeroBits
> 21) // per-arch?
1360 DPRINT1("Invalid zero bits\n");
1361 return STATUS_INVALID_PARAMETER_4
;
1364 /* Check for invalid inherit disposition */
1365 if ((InheritDisposition
> ViewUnmap
) || (InheritDisposition
< ViewShare
))
1367 DPRINT1("Invalid inherit disposition\n");
1368 return STATUS_INVALID_PARAMETER_8
;
1371 /* Allow only valid allocation types */
1372 if ((AllocationType
& ~(MEM_TOP_DOWN
| MEM_LARGE_PAGES
| MEM_DOS_LIM
|
1373 SEC_NO_CHANGE
| MEM_RESERVE
)))
1375 DPRINT1("Invalid allocation type\n");
1376 return STATUS_INVALID_PARAMETER_9
;
1379 /* Convert the protection mask, and validate it */
1380 ProtectionMask
= MiMakeProtectionMask(Protect
);
1381 if (ProtectionMask
== MM_INVALID_PROTECTION
)
1383 DPRINT1("Invalid page protection\n");
1384 return STATUS_INVALID_PAGE_PROTECTION
;
1387 /* Now convert the protection mask into desired section access mask */
1388 DesiredAccess
= MmMakeSectionAccess
[ProtectionMask
& 0x7];
1390 /* Assume no section offset */
1391 SafeSectionOffset
.QuadPart
= 0;
1396 /* Check for unsafe parameters */
1397 if (PreviousMode
!= KernelMode
)
1399 /* Probe the parameters */
1400 ProbeForWritePointer(BaseAddress
);
1401 ProbeForWriteSize_t(ViewSize
);
1404 /* Check if a section offset was given */
1407 /* Check for unsafe parameters and capture section offset */
1408 if (PreviousMode
!= KernelMode
) ProbeForWriteLargeInteger(SectionOffset
);
1409 SafeSectionOffset
= *SectionOffset
;
1412 /* Capture the other parameters */
1413 SafeBaseAddress
= *BaseAddress
;
1414 SafeViewSize
= *ViewSize
;
1416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1418 /* Return the exception code */
1419 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1423 /* Check for kernel-mode address */
1424 if (SafeBaseAddress
> MM_HIGHEST_VAD_ADDRESS
)
1426 DPRINT1("Kernel base not allowed\n");
1427 return STATUS_INVALID_PARAMETER_3
;
1430 /* Check for range entering kernel-mode */
1431 if (((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
- (ULONG_PTR
)SafeBaseAddress
) < SafeViewSize
)
1433 DPRINT1("Overflowing into kernel base not allowed\n");
1434 return STATUS_INVALID_PARAMETER_3
;
1437 /* Check for invalid zero bits */
1438 if (((ULONG_PTR
)SafeBaseAddress
+ SafeViewSize
) > (0xFFFFFFFF >> ZeroBits
)) // arch?
1440 DPRINT1("Invalid zero bits\n");
1441 return STATUS_INVALID_PARAMETER_4
;
1444 /* Reference the process */
1445 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1446 PROCESS_VM_OPERATION
,
1451 if (!NT_SUCCESS(Status
)) return Status
;
1453 /* Reference the section */
1454 Status
= ObReferenceObjectByHandle(SectionHandle
,
1456 MmSectionObjectType
,
1460 if (!NT_SUCCESS(Status
))
1462 ObDereferenceObject(Process
);
1466 /* Now do the actual mapping */
1467 Status
= MmMapViewOfSection(Section
,
1478 /* Check if this is an image for the current process */
1479 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
1480 (Process
== PsGetCurrentProcess()) &&
1481 ((Status
!= STATUS_IMAGE_NOT_AT_BASE
) ||
1482 (Status
!= STATUS_CONFLICTING_ADDRESSES
)))
1484 /* Notify the debugger */
1485 DbgkMapViewOfSection(Section
,
1487 SafeSectionOffset
.LowPart
,
1491 /* Return data only on success */
1492 if (NT_SUCCESS(Status
))
1497 /* Return parameters to user */
1498 *BaseAddress
= SafeBaseAddress
;
1499 *ViewSize
= SafeViewSize
;
1500 if (SectionOffset
) *SectionOffset
= SafeSectionOffset
;
1502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1509 /* Dereference all objects and return status */
1510 ObDereferenceObject(Section
);
1511 ObDereferenceObject(Process
);
1517 NtUnmapViewOfSection(IN HANDLE ProcessHandle
,
1518 IN PVOID BaseAddress
)
1522 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1524 /* Don't allowing mapping kernel views */
1525 if ((PreviousMode
== UserMode
) && (BaseAddress
> MM_HIGHEST_USER_ADDRESS
))
1527 DPRINT1("Trying to unmap a kernel view\n");
1528 return STATUS_NOT_MAPPED_VIEW
;
1531 /* Reference the process */
1532 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1533 PROCESS_VM_OPERATION
,
1538 if (!NT_SUCCESS(Status
)) return Status
;
1540 /* Unmap the view */
1541 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
1543 /* Dereference the process and return status */
1544 ObDereferenceObject(Process
);
1550 NtExtendSection(IN HANDLE SectionHandle
,
1551 IN OUT PLARGE_INTEGER NewMaximumSize
)
1553 LARGE_INTEGER SafeNewMaximumSize
;
1554 PROS_SECTION_OBJECT Section
;
1556 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1558 /* Check for user-mode parameters */
1559 if (PreviousMode
!= KernelMode
)
1564 /* Probe and capture the maximum size, it's both read and write */
1565 ProbeForWriteLargeInteger(NewMaximumSize
);
1566 SafeNewMaximumSize
= *NewMaximumSize
;
1568 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1570 /* Return the exception code */
1571 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1577 /* Just read the size directly */
1578 SafeNewMaximumSize
= *NewMaximumSize
;
1581 /* Reference the section */
1582 Status
= ObReferenceObjectByHandle(SectionHandle
,
1583 SECTION_EXTEND_SIZE
,
1584 MmSectionObjectType
,
1588 if (!NT_SUCCESS(Status
)) return Status
;
1590 /* Really this should go in MmExtendSection */
1591 if (!(Section
->AllocationAttributes
& SEC_FILE
))
1593 DPRINT1("Not extending a file\n");
1594 ObDereferenceObject(Section
);
1595 return STATUS_SECTION_NOT_EXTENDED
;
1598 /* FIXME: Do the work */
1600 /* Dereference the section */
1601 ObDereferenceObject(Section
);
1606 /* Write back the new size */
1607 *NewMaximumSize
= SafeNewMaximumSize
;
1609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1615 /* Return the status */
1616 return STATUS_NOT_IMPLEMENTED
;
1619 /* PUBLIC FUNCTIONS ***********************************************************/
1626 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1637 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
1638 IN BOOLEAN DelayClose
)
1649 MmMapViewInSessionSpace(IN PVOID Section
,
1650 OUT PVOID
*MappedBase
,
1651 IN OUT PSIZE_T ViewSize
)
1654 return STATUS_NOT_IMPLEMENTED
;
1662 MmUnmapViewInSessionSpace(IN PVOID MappedBase
)
1665 return STATUS_NOT_IMPLEMENTED
;