2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/procsup.c
5 * PURPOSE: ARM Memory Manager Process Related Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::PROCSUP"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 extern MM_SYSTEMSIZE MmSystemSize
;
21 /* PRIVATE FUNCTIONS **********************************************************/
25 MiRosTakeOverPebTebRanges(IN PEPROCESS Process
)
28 PMEMORY_AREA MemoryArea
;
29 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
30 PVOID AllocatedBase
= (PVOID
)MI_LOWEST_VAD_ADDRESS
;
31 BoundaryAddressMultiple
.QuadPart
= 0;
33 Status
= MmCreateMemoryArea(&Process
->Vm
,
34 MEMORY_AREA_OWNED_BY_ARM3
,
36 ((ULONG_PTR
)MM_HIGHEST_USER_ADDRESS
- 1) -
37 (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
,
42 BoundaryAddressMultiple
);
43 ASSERT(NT_SUCCESS(Status
));
48 MiCreatePebOrTeb(IN PEPROCESS Process
,
52 PETHREAD Thread
= PsGetCurrentThread();
56 ULONG_PTR StartAddress
, EndAddress
;
57 LARGE_INTEGER CurrentTime
;
60 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD_LONG
), 'ldaV');
61 if (!Vad
) return STATUS_NO_MEMORY
;
63 /* Setup the primary flags with the size, and make it commited, private, RW */
65 Vad
->u
.VadFlags
.CommitCharge
= BYTES_TO_PAGES(Size
);
66 Vad
->u
.VadFlags
.MemCommit
= TRUE
;
67 Vad
->u
.VadFlags
.PrivateMemory
= TRUE
;
68 Vad
->u
.VadFlags
.Protection
= MM_READWRITE
;
69 Vad
->u
.VadFlags
.NoChange
= TRUE
;
71 /* Setup the secondary flags to make it a secured, writable, long VAD */
72 Vad
->u2
.LongFlags2
= 0;
73 Vad
->u2
.VadFlags2
.OneSecured
= TRUE
;
74 Vad
->u2
.VadFlags2
.LongVad
= TRUE
;
75 Vad
->u2
.VadFlags2
.ReadOnly
= FALSE
;
77 /* Lock the process address space */
78 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
80 /* Check if this is a PEB creation */
81 if (Size
== sizeof(PEB
))
83 /* Start at the highest valid address */
84 StartAddress
= (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1;
86 /* Select the random coefficient */
87 KeQueryTickCount(&CurrentTime
);
88 CurrentTime
.LowPart
&= ((64 * _1KB
) >> PAGE_SHIFT
) - 1;
89 if (CurrentTime
.LowPart
<= 1) CurrentTime
.LowPart
= 2;
90 RandomCoeff
= CurrentTime
.LowPart
<< PAGE_SHIFT
;
92 /* Select the highest valid address minus the random coefficient */
93 StartAddress
-= RandomCoeff
;
94 EndAddress
= StartAddress
+ ROUND_TO_PAGES(Size
) - 1;
96 /* See if this VA range can be obtained */
97 if (!MiCheckForConflictingNode(StartAddress
>> PAGE_SHIFT
,
98 EndAddress
>> PAGE_SHIFT
,
101 /* No conflict, use this address */
102 *Base
= StartAddress
;
107 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
108 Status
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
109 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1,
113 ASSERT(NT_SUCCESS(Status
));
116 /* Validate that it came from the VAD ranges */
117 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
119 /* Build the rest of the VAD now */
120 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
121 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
122 Vad
->u3
.Secured
.StartVpn
= *Base
;
123 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
124 Vad
->u1
.Parent
= NULL
;
126 /* FIXME: Should setup VAD bitmap */
127 Status
= STATUS_SUCCESS
;
129 /* Pretend as if we own the working set */
130 MiLockProcessWorkingSet(Process
, Thread
);
133 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
134 Process
->VadRoot
.NodeHint
= Vad
;
135 MiInsertNode((PVOID
)Vad
, &Process
->VadRoot
);
137 /* Release the working set */
138 MiUnlockProcessWorkingSet(Process
, Thread
);
140 /* Release the address space lock */
141 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
143 /* Return the status */
144 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
150 MmDeleteTeb(IN PEPROCESS Process
,
154 PETHREAD Thread
= PsGetCurrentThread();
156 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
157 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
159 /* TEB is one page */
160 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
162 /* Attach to the process */
163 KeAttachProcess(&Process
->Pcb
);
165 /* Lock the process address space */
166 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
168 /* Find the VAD, make sure it's a TEB VAD */
169 Vad
= MiLocateAddress(Teb
);
170 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
172 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
174 /* Bug in the AVL code? */
175 DPRINT1("Corrupted VAD!\n");
179 /* Sanity checks for a valid TEB VAD */
180 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
181 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
182 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
183 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
185 /* Lock the working set */
186 MiLockProcessWorkingSet(Process
, Thread
);
188 /* Remove this VAD from the tree */
189 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
190 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
192 /* Release the working set */
193 MiUnlockProcessWorkingSet(Process
, Thread
);
199 /* Release the address space lock */
200 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
208 MmDeleteKernelStack(IN PVOID StackBase
,
212 PFN_NUMBER StackPages
, PageFrameNumber
;//, PageTableFrameNumber;
213 PMMPFN Pfn1
;//, Pfn2;
218 // This should be the guard page, so decrement by one
220 PointerPte
= MiAddressToPte(StackBase
);
224 // Calculate pages used
226 StackPages
= BYTES_TO_PAGES(GuiStack
?
227 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
229 /* Acquire the PFN lock */
230 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
235 for (i
= 0; i
< StackPages
; i
++)
238 // Check if this is a valid PTE
240 if (PointerPte
->u
.Hard
.Valid
== 1)
242 /* Get the PTE's page */
243 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
244 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
245 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
246 /* Now get the page of the page table mapping it */
247 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
248 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
250 /* Remove a shared reference, since the page is going away */
251 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
253 /* Set the special pending delete marker */
254 Pfn1
->PteAddress
= (PMMPTE
)((ULONG_PTR
)Pfn1
->PteAddress
| 1);
256 /* And now delete the actual stack page */
257 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
267 // We should be at the guard page now
269 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
271 /* Release the PFN lock */
272 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
277 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
282 MmCreateKernelStack(IN BOOLEAN GuiStack
,
285 PFN_NUMBER StackPtes
, StackPages
;
286 PMMPTE PointerPte
, StackPte
;
288 MMPTE TempPte
, InvalidPte
;
290 PFN_NUMBER PageFrameIndex
;
294 // Calculate pages needed
299 // We'll allocate 64KB stack, but only commit 12K
301 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
302 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
308 // We'll allocate 12K and that's it
310 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
311 StackPages
= StackPtes
;
315 // Reserve stack pages, plus a guard page
317 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
318 if (!StackPte
) return NULL
;
321 // Get the stack address
323 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
326 // Select the right PTE address where we actually start committing pages
328 PointerPte
= StackPte
;
329 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
330 KERNEL_LARGE_STACK_COMMIT
);
333 /* Setup the temporary invalid PTE */
334 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
336 /* Setup the template stack PTE */
337 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
340 // Acquire the PFN DB lock
342 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
345 // Loop each stack page
347 for (i
= 0; i
< StackPages
; i
++)
354 /* Get a page and write the current invalid PTE */
355 PageFrameIndex
= MiRemoveAnyPage(0);
356 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
358 /* Initialize the PFN entry for this page */
359 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
361 /* Write the valid PTE */
362 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
363 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
367 (VOID
)InterlockedExchangeAddUL(&MiMemoryConsumers
[MC_NPPOOL
].PagesUsed
, StackPages
);
370 // Release the PFN lock
372 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
375 // Return the stack address
382 MmGrowKernelStackEx(IN PVOID StackPointer
,
385 PKTHREAD Thread
= KeGetCurrentThread();
386 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
387 PFN_NUMBER StackPages
;
389 MMPTE TempPte
, InvalidPte
;
390 PFN_NUMBER PageFrameIndex
;
393 // Make sure the stack did not overflow
395 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
396 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
399 // Get the current stack limit
401 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
402 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
405 // Get the new one and make sure this isn't a retarded request
407 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
408 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
411 // Now make sure you're not going past the reserved space
413 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
414 KERNEL_LARGE_STACK_SIZE
));
415 if (NewLimitPte
< LastPte
)
420 DPRINT1("Thread wants too much stack\n");
421 return STATUS_STACK_OVERFLOW
;
425 // Calculate the number of new pages
428 StackPages
= (LimitPte
- NewLimitPte
+ 1);
430 /* Setup the temporary invalid PTE */
431 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
434 // Acquire the PFN DB lock
436 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
439 // Loop each stack page
441 while (LimitPte
>= NewLimitPte
)
443 /* Get a page and write the current invalid PTE */
444 PageFrameIndex
= MiRemoveAnyPage(0);
445 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
447 /* Initialize the PFN entry for this page */
448 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
450 /* Setup the template stack PTE */
451 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
453 /* Write the valid PTE */
454 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
458 // Release the PFN lock
460 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
465 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
466 return STATUS_SUCCESS
;
471 MmGrowKernelStack(IN PVOID StackPointer
)
474 // Call the extended version
476 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
481 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
482 IN UCHAR MemoryPriority
)
487 // Check if we have less then 16MB of Physical Memory
489 if ((MmSystemSize
== MmSmallSystem
) &&
490 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
493 // Always use background priority
495 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
499 // Save the old priority and update it
501 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
502 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
505 // Return the old priority
512 MmGetSessionLocaleId(VOID
)
518 // Get the current process
520 Process
= PsGetCurrentProcess();
523 // Check if it's the Session Leader
525 if (Process
->Vm
.Flags
.SessionLeader
)
528 // Make sure it has a valid Session
530 if (Process
->Session
)
536 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
542 // Not a session leader, return the default
544 return PsDefaultThreadLocaleId
;
549 MmCreatePeb(IN PEPROCESS Process
,
550 IN PINITIAL_PEB InitialPeb
,
554 LARGE_INTEGER SectionOffset
;
556 PVOID TableBase
= NULL
;
557 PIMAGE_NT_HEADERS NtHeaders
;
558 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
560 USHORT Characteristics
;
561 KAFFINITY ProcessAffinityMask
= 0;
562 SectionOffset
.QuadPart
= (ULONGLONG
)0;
568 KeAttachProcess(&Process
->Pcb
);
573 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
574 ASSERT(NT_SUCCESS(Status
));
579 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
589 if (!NT_SUCCESS(Status
)) return Status
;
592 // Use SEH in case we can't load the PEB
597 // Initialize the PEB
599 RtlZeroMemory(Peb
, sizeof(PEB
));
604 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
605 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
606 Peb
->Mutant
= InitialPeb
->Mutant
;
607 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
612 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
613 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
614 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
617 // Default Version Data (could get changed below)
619 Peb
->OSMajorVersion
= NtMajorVersion
;
620 Peb
->OSMinorVersion
= NtMinorVersion
;
621 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
622 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
623 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
626 // Heap and Debug Data
628 Peb
->NumberOfProcessors
= KeNumberProcessors
;
629 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
630 Peb
->NtGlobalFlag
= NtGlobalFlag
;
631 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
632 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
633 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
634 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
635 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
636 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
638 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
639 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
644 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
652 _SEH2_YIELD(return _SEH2_GetExceptionCode());
657 // Use SEH in case we can't load the image
664 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
665 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
667 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
673 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
683 // Use SEH in case we can't load the headers
688 // Get the Image Config Data too
690 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
692 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
699 ProbeForRead(ImageConfigData
,
700 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
705 // Write subsystem data
707 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
708 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
709 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
712 // Check for version data
714 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
717 // Extract values and write them
719 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
720 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
721 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
722 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
726 // Process the image config data overrides if specfied
728 if (ImageConfigData
!= NULL
)
731 // Process CSD version override
733 if (ImageConfigData
->CSDVersion
)
738 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
742 // Process affinity mask ovverride
744 if (ImageConfigData
->ProcessAffinityMask
)
749 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
754 // Check if this is a UP image
755 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
758 // Force it to use CPU 0
760 Peb
->ImageProcessAffinityMask
= 0;
765 // Whatever was configured
767 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
776 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
782 // Detach from the Process
786 return STATUS_SUCCESS
;
791 MmCreateTeb(IN PEPROCESS Process
,
792 IN PCLIENT_ID ClientId
,
793 IN PINITIAL_TEB InitialTeb
,
797 NTSTATUS Status
= STATUS_SUCCESS
;
803 KeAttachProcess(&Process
->Pcb
);
808 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
809 ASSERT(NT_SUCCESS(Status
));
812 // Use SEH in case we can't load the TEB
817 // Initialize the PEB
819 RtlZeroMemory(Teb
, sizeof(TEB
));
824 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
825 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
828 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
830 Teb
->NtTib
.Version
= 30 << 8;
835 Teb
->ClientId
= *ClientId
;
836 Teb
->RealClientId
= *ClientId
;
837 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
838 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
841 // Check if we have a grandparent TEB
843 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
844 (InitialTeb
->PreviousStackLimit
== NULL
))
847 // Use initial TEB values
849 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
850 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
851 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
856 // Use grandparent TEB values
858 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
859 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
863 // Initialize the static unicode string
865 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
866 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
873 Status
= _SEH2_GetExceptionCode();
887 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
888 IN PEPROCESS ProcessClone OPTIONAL
,
889 IN PVOID Section OPTIONAL
,
891 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
893 NTSTATUS Status
= STATUS_SUCCESS
;
896 PROS_SECTION_OBJECT SectionObject
= Section
;
900 PFN_NUMBER PageFrameNumber
;
901 UNICODE_STRING FileName
;
906 /* We should have a PDE */
907 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
908 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
910 /* Attach to the process */
911 KeAttachProcess(&Process
->Pcb
);
913 /* The address space should now been in phase 1 or 0 */
914 ASSERT(Process
->AddressSpaceInitialized
<= 1);
915 Process
->AddressSpaceInitialized
= 2;
917 /* Initialize the Addresss Space lock */
918 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
919 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
921 /* Initialize AVL tree */
922 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
923 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
925 /* Lock PFN database */
926 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
928 /* Setup the PFN for the PDE base of this process */
929 PointerPte
= MiAddressToPte(PDE_BASE
);
930 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
931 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
933 /* Do the same for hyperspace */
934 PointerPde
= MiAddressToPde(HYPER_SPACE
);
935 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
936 MiInitializePfn(PageFrameNumber
, PointerPde
, TRUE
);
938 /* Release PFN lock */
939 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
941 /* Lock the VAD, ARM3-owned ranges away */
942 MiRosTakeOverPebTebRanges(Process
);
944 /* Check if there's a Section Object */
947 /* Determine the image file name and save it to EPROCESS */
948 FileName
= SectionObject
->FileObject
->FileName
;
949 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
952 /* Loop the file name*/
953 while (Source
> FileName
.Buffer
)
955 /* Make sure this isn't a backslash */
956 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
958 /* If so, stop it here */
964 /* Otherwise, keep going */
970 /* Copy the to the process and truncate it to 15 characters if necessary */
971 Destination
= Process
->ImageFileName
;
972 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
973 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
974 *Destination
= ANSI_NULL
;
976 /* Check if caller wants an audit name */
979 /* Setup the audit name */
980 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
983 if (!NT_SUCCESS(Status
))
991 /* Map the section */
992 Status
= MmMapViewOfSection(Section
,
1003 /* Save the pointer */
1004 Process
->SectionBaseAddress
= ImageBase
;
1007 /* Be nice and detach */
1010 /* Return status to caller */
1016 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1017 IN PULONG_PTR DirectoryTableBase
)
1019 /* Share the directory base with the idle process */
1020 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1021 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1023 /* Initialize the Addresss Space */
1024 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1025 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1026 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1027 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1028 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1031 Process
->HasAddressSpace
= TRUE
;//??
1032 return STATUS_SUCCESS
;
1037 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1039 /* Lock the VAD, ARM3-owned ranges away */
1040 MiRosTakeOverPebTebRanges(Process
);
1041 return STATUS_SUCCESS
;
1045 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1048 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1049 IN PEPROCESS Process
,
1050 OUT PULONG_PTR DirectoryTableBase
)
1053 PFN_NUMBER PdeIndex
, HyperIndex
;
1055 MMPTE TempPte
, PdePte
;
1059 /* No page colors yet */
1060 Process
->NextPageColor
= 0;
1062 /* Setup the hyperspace lock */
1063 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1065 /* Lock PFN database */
1066 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1068 /* Get a page for the PDE */
1069 PdeIndex
= MiRemoveAnyPage(0);
1070 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1071 MiZeroPhysicalPage(PdeIndex
);
1072 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1074 /* Get a page for hyperspace */
1075 HyperIndex
= MiRemoveAnyPage(0);
1076 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1077 MiZeroPhysicalPage(HyperIndex
);
1079 /* Switch to phase 1 initialization */
1080 ASSERT(Process
->AddressSpaceInitialized
== 0);
1081 Process
->AddressSpaceInitialized
= 1;
1083 /* Set the base directory pointers */
1084 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1085 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1087 /* Make sure we don't already have a page directory setup */
1088 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1090 /* Insert us into the Mm process list */
1091 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1093 /* Get a PTE to map the page directory */
1094 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1095 ASSERT(PointerPte
!= NULL
);
1098 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1103 /* Set it dirty and map it */
1104 PdePte
.u
.Hard
.Dirty
= TRUE
;
1105 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1107 /* Now get the page directory (which we'll double map, so call it a page table */
1108 SystemTable
= MiPteToAddress(PointerPte
);
1110 /* Copy all the kernel mappings */
1111 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1113 RtlCopyMemory(&SystemTable
[PdeOffset
],
1114 MiAddressToPde(MmSystemRangeStart
),
1115 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1117 /* Now write the PTE/PDE entry for hyperspace itself */
1118 TempPte
= ValidKernelPte
;
1119 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1120 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1121 SystemTable
[PdeOffset
] = TempPte
;
1125 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1127 /* Now do the x86 trick of making the PDE a page table itself */
1128 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1129 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1130 SystemTable
[PdeOffset
] = TempPte
;
1132 /* Let go of the system PTE */
1133 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1140 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1143 PMM_AVL_TABLE VadTree
;
1144 PETHREAD Thread
= PsGetCurrentThread();
1146 /* Lock the process address space from changes */
1147 MmLockAddressSpace(&Process
->Vm
);
1149 /* Enumerate the VADs */
1150 VadTree
= &Process
->VadRoot
;
1151 DPRINT("Cleaning up VADs: %d\n", VadTree
->NumberGenericTableElements
);
1152 while (VadTree
->NumberGenericTableElements
)
1154 /* Grab the current VAD */
1155 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1157 /* Lock the working set */
1158 MiLockProcessWorkingSet(Process
, Thread
);
1160 /* Remove this VAD from the tree */
1161 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1162 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
1163 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1164 DPRINT("Moving on: %d\n", VadTree
->NumberGenericTableElements
);
1166 /* Check if this VAD was the hint */
1167 if (VadTree
->NodeHint
== Vad
)
1169 /* Get a new hint, unless we're empty now, in which case nothing */
1170 VadTree
->NodeHint
= VadTree
->BalancedRoot
.RightChild
;
1171 if (!VadTree
->NumberGenericTableElements
) VadTree
->NodeHint
= NULL
;
1174 /* Only PEB/TEB VADs supported for now */
1175 ASSERT(Vad
->u
.VadFlags
.PrivateMemory
== 1);
1176 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1178 /* Release the working set */
1179 MiUnlockProcessWorkingSet(Process
, Thread
);
1181 /* Free the VAD memory */
1185 /* Release the address space */
1186 MmUnlockAddressSpace(&Process
->Vm
);
1189 /* SYSTEM CALLS ***************************************************************/
1193 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1194 IN OUT PULONG_PTR NumberOfPages
,
1195 IN OUT PULONG_PTR UserPfnArray
)
1198 return STATUS_NOT_IMPLEMENTED
;
1203 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1204 IN ULONG_PTR NumberOfPages
,
1205 IN OUT PULONG_PTR UserPfnArray
)
1208 return STATUS_NOT_IMPLEMENTED
;
1213 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1214 IN ULONG_PTR NumberOfPages
,
1215 IN OUT PULONG_PTR UserPfnArray
)
1218 return STATUS_NOT_IMPLEMENTED
;
1223 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1224 IN OUT PULONG_PTR NumberOfPages
,
1225 IN OUT PULONG_PTR UserPfnArray
)
1228 return STATUS_NOT_IMPLEMENTED
;