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
;
58 TABLE_SEARCH_RESULT Result
= TableFoundNode
;
59 PMMADDRESS_NODE Parent
;
62 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD_LONG
), 'ldaV');
63 if (!Vad
) return STATUS_NO_MEMORY
;
65 /* Setup the primary flags with the size, and make it commited, private, RW */
67 Vad
->u
.VadFlags
.CommitCharge
= BYTES_TO_PAGES(Size
);
68 Vad
->u
.VadFlags
.MemCommit
= TRUE
;
69 Vad
->u
.VadFlags
.PrivateMemory
= TRUE
;
70 Vad
->u
.VadFlags
.Protection
= MM_READWRITE
;
71 Vad
->u
.VadFlags
.NoChange
= TRUE
;
73 /* Setup the secondary flags to make it a secured, writable, long VAD */
74 Vad
->u2
.LongFlags2
= 0;
75 Vad
->u2
.VadFlags2
.OneSecured
= TRUE
;
76 Vad
->u2
.VadFlags2
.LongVad
= TRUE
;
77 Vad
->u2
.VadFlags2
.ReadOnly
= FALSE
;
79 /* Lock the process address space */
80 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
82 /* Check if this is a PEB creation */
83 if (Size
== sizeof(PEB
))
85 /* Start at the highest valid address */
86 StartAddress
= (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1;
88 /* Select the random coefficient */
89 KeQueryTickCount(&CurrentTime
);
90 CurrentTime
.LowPart
&= ((64 * _1KB
) >> PAGE_SHIFT
) - 1;
91 if (CurrentTime
.LowPart
<= 1) CurrentTime
.LowPart
= 2;
92 RandomCoeff
= CurrentTime
.LowPart
<< PAGE_SHIFT
;
94 /* Select the highest valid address minus the random coefficient */
95 StartAddress
-= RandomCoeff
;
96 EndAddress
= StartAddress
+ ROUND_TO_PAGES(Size
) - 1;
98 /* Try to find something below the random upper margin */
99 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
107 /* Check for success. TableFoundNode means nothing free. */
108 if (Result
== TableFoundNode
)
110 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
111 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
112 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1,
117 /* Bail out, if still nothing free was found */
118 if (Result
== TableFoundNode
) return STATUS_NO_MEMORY
;
121 /* Validate that it came from the VAD ranges */
122 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
124 /* Build the rest of the VAD now */
125 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
126 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
127 Vad
->u3
.Secured
.StartVpn
= *Base
;
128 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
129 Vad
->u1
.Parent
= NULL
;
131 /* FIXME: Should setup VAD bitmap */
132 Status
= STATUS_SUCCESS
;
134 /* Pretend as if we own the working set */
135 MiLockProcessWorkingSet(Process
, Thread
);
138 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
139 Process
->VadRoot
.NodeHint
= Vad
;
140 MiInsertNode(&Process
->VadRoot
, (PVOID
)Vad
, Parent
, Result
);
142 /* Release the working set */
143 MiUnlockProcessWorkingSet(Process
, Thread
);
145 /* Release the address space lock */
146 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
148 /* Return the status */
149 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
155 MmDeleteTeb(IN PEPROCESS Process
,
159 PETHREAD Thread
= PsGetCurrentThread();
161 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
162 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
164 /* TEB is one page */
165 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
167 /* Attach to the process */
168 KeAttachProcess(&Process
->Pcb
);
170 /* Lock the process address space */
171 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
173 /* Find the VAD, make sure it's a TEB VAD */
174 Vad
= MiLocateAddress(Teb
);
175 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
177 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
179 /* Bug in the AVL code? */
180 DPRINT1("Corrupted VAD!\n");
184 /* Sanity checks for a valid TEB VAD */
185 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
186 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
187 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
188 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
190 /* Lock the working set */
191 MiLockProcessWorkingSet(Process
, Thread
);
193 /* Remove this VAD from the tree */
194 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
195 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
197 /* Release the working set */
198 MiUnlockProcessWorkingSet(Process
, Thread
);
204 /* Release the address space lock */
205 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
213 MmDeleteKernelStack(IN PVOID StackBase
,
217 PFN_NUMBER StackPages
, PageFrameNumber
;//, PageTableFrameNumber;
218 PMMPFN Pfn1
;//, Pfn2;
223 // This should be the guard page, so decrement by one
225 PointerPte
= MiAddressToPte(StackBase
);
229 // Calculate pages used
231 StackPages
= BYTES_TO_PAGES(GuiStack
?
232 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
234 /* Acquire the PFN lock */
235 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
240 for (i
= 0; i
< StackPages
; i
++)
243 // Check if this is a valid PTE
245 if (PointerPte
->u
.Hard
.Valid
== 1)
247 /* Get the PTE's page */
248 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
249 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
250 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
251 /* Now get the page of the page table mapping it */
252 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
253 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
255 /* Remove a shared reference, since the page is going away */
256 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
258 /* Set the special pending delete marker */
259 Pfn1
->PteAddress
= (PMMPTE
)((ULONG_PTR
)Pfn1
->PteAddress
| 1);
261 /* And now delete the actual stack page */
262 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
272 // We should be at the guard page now
274 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
276 /* Release the PFN lock */
277 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
282 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
287 MmCreateKernelStack(IN BOOLEAN GuiStack
,
290 PFN_NUMBER StackPtes
, StackPages
;
291 PMMPTE PointerPte
, StackPte
;
293 MMPTE TempPte
, InvalidPte
;
295 PFN_NUMBER PageFrameIndex
;
299 // Calculate pages needed
304 // We'll allocate 64KB stack, but only commit 12K
306 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
307 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
313 // We'll allocate 12K and that's it
315 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
316 StackPages
= StackPtes
;
320 // Reserve stack pages, plus a guard page
322 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
323 if (!StackPte
) return NULL
;
326 // Get the stack address
328 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
331 // Select the right PTE address where we actually start committing pages
333 PointerPte
= StackPte
;
334 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
335 KERNEL_LARGE_STACK_COMMIT
);
338 /* Setup the temporary invalid PTE */
339 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
341 /* Setup the template stack PTE */
342 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
345 // Acquire the PFN DB lock
347 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
350 // Loop each stack page
352 for (i
= 0; i
< StackPages
; i
++)
359 /* Get a page and write the current invalid PTE */
360 PageFrameIndex
= MiRemoveAnyPage(0);
361 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
363 /* Initialize the PFN entry for this page */
364 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
366 /* Write the valid PTE */
367 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
368 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
372 (VOID
)InterlockedExchangeAddUL(&MiMemoryConsumers
[MC_NPPOOL
].PagesUsed
, StackPages
);
375 // Release the PFN lock
377 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
380 // Return the stack address
387 MmGrowKernelStackEx(IN PVOID StackPointer
,
390 PKTHREAD Thread
= KeGetCurrentThread();
391 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
393 MMPTE TempPte
, InvalidPte
;
394 PFN_NUMBER PageFrameIndex
;
397 // Make sure the stack did not overflow
399 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
400 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
403 // Get the current stack limit
405 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
406 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
409 // Get the new one and make sure this isn't a retarded request
411 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
412 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
415 // Now make sure you're not going past the reserved space
417 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
418 KERNEL_LARGE_STACK_SIZE
));
419 if (NewLimitPte
< LastPte
)
424 DPRINT1("Thread wants too much stack\n");
425 return STATUS_STACK_OVERFLOW
;
429 // Calculate the number of new pages
433 /* Setup the temporary invalid PTE */
434 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
437 // Acquire the PFN DB lock
439 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
442 // Loop each stack page
444 while (LimitPte
>= NewLimitPte
)
446 /* Get a page and write the current invalid PTE */
447 PageFrameIndex
= MiRemoveAnyPage(0);
448 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
450 /* Initialize the PFN entry for this page */
451 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
453 /* Setup the template stack PTE */
454 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
456 /* Write the valid PTE */
457 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
461 // Release the PFN lock
463 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
468 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
469 return STATUS_SUCCESS
;
474 MmGrowKernelStack(IN PVOID StackPointer
)
477 // Call the extended version
479 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
484 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
485 IN UCHAR MemoryPriority
)
490 // Check if we have less then 16MB of Physical Memory
492 if ((MmSystemSize
== MmSmallSystem
) &&
493 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
496 // Always use background priority
498 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
502 // Save the old priority and update it
504 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
505 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
508 // Return the old priority
515 MmGetSessionLocaleId(VOID
)
521 // Get the current process
523 Process
= PsGetCurrentProcess();
526 // Check if it's the Session Leader
528 if (Process
->Vm
.Flags
.SessionLeader
)
531 // Make sure it has a valid Session
533 if (Process
->Session
)
539 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
545 // Not a session leader, return the default
547 return PsDefaultThreadLocaleId
;
552 MmCreatePeb(IN PEPROCESS Process
,
553 IN PINITIAL_PEB InitialPeb
,
557 LARGE_INTEGER SectionOffset
;
559 PVOID TableBase
= NULL
;
560 PIMAGE_NT_HEADERS NtHeaders
;
561 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
563 USHORT Characteristics
;
564 KAFFINITY ProcessAffinityMask
= 0;
565 SectionOffset
.QuadPart
= (ULONGLONG
)0;
571 KeAttachProcess(&Process
->Pcb
);
576 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
577 ASSERT(NT_SUCCESS(Status
));
582 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
592 if (!NT_SUCCESS(Status
)) return Status
;
595 // Use SEH in case we can't load the PEB
600 // Initialize the PEB
602 RtlZeroMemory(Peb
, sizeof(PEB
));
607 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
608 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
609 Peb
->Mutant
= InitialPeb
->Mutant
;
610 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
615 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
616 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
617 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
620 // Default Version Data (could get changed below)
622 Peb
->OSMajorVersion
= NtMajorVersion
;
623 Peb
->OSMinorVersion
= NtMinorVersion
;
624 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
625 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
626 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
629 // Heap and Debug Data
631 Peb
->NumberOfProcessors
= KeNumberProcessors
;
632 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
633 Peb
->NtGlobalFlag
= NtGlobalFlag
;
634 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
635 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
636 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
637 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
638 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
639 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
641 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
642 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
647 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
655 _SEH2_YIELD(return _SEH2_GetExceptionCode());
660 // Use SEH in case we can't load the image
667 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
668 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
676 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
686 // Use SEH in case we can't load the headers
691 // Get the Image Config Data too
693 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
695 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
702 ProbeForRead(ImageConfigData
,
703 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
708 // Write subsystem data
710 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
711 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
712 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
715 // Check for version data
717 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
720 // Extract values and write them
722 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
723 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
724 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
725 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
729 // Process the image config data overrides if specfied
731 if (ImageConfigData
!= NULL
)
734 // Process CSD version override
736 if (ImageConfigData
->CSDVersion
)
741 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
745 // Process affinity mask ovverride
747 if (ImageConfigData
->ProcessAffinityMask
)
752 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
757 // Check if this is a UP image
758 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
761 // Force it to use CPU 0
763 Peb
->ImageProcessAffinityMask
= 0;
768 // Whatever was configured
770 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
779 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
785 // Detach from the Process
789 return STATUS_SUCCESS
;
794 MmCreateTeb(IN PEPROCESS Process
,
795 IN PCLIENT_ID ClientId
,
796 IN PINITIAL_TEB InitialTeb
,
800 NTSTATUS Status
= STATUS_SUCCESS
;
806 KeAttachProcess(&Process
->Pcb
);
811 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
812 ASSERT(NT_SUCCESS(Status
));
815 // Use SEH in case we can't load the TEB
820 // Initialize the PEB
822 RtlZeroMemory(Teb
, sizeof(TEB
));
827 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
828 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
831 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
833 Teb
->NtTib
.Version
= 30 << 8;
838 Teb
->ClientId
= *ClientId
;
839 Teb
->RealClientId
= *ClientId
;
840 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
841 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
844 // Check if we have a grandparent TEB
846 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
847 (InitialTeb
->PreviousStackLimit
== NULL
))
850 // Use initial TEB values
852 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
853 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
854 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
859 // Use grandparent TEB values
861 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
862 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
866 // Initialize the static unicode string
868 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
869 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
871 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
876 Status
= _SEH2_GetExceptionCode();
890 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
891 IN PEPROCESS ProcessClone OPTIONAL
,
892 IN PVOID Section OPTIONAL
,
894 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
896 NTSTATUS Status
= STATUS_SUCCESS
;
899 PROS_SECTION_OBJECT SectionObject
= Section
;
903 PFN_NUMBER PageFrameNumber
;
904 UNICODE_STRING FileName
;
909 /* We should have a PDE */
910 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
911 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
913 /* Attach to the process */
914 KeAttachProcess(&Process
->Pcb
);
916 /* The address space should now been in phase 1 or 0 */
917 ASSERT(Process
->AddressSpaceInitialized
<= 1);
918 Process
->AddressSpaceInitialized
= 2;
920 /* Initialize the Addresss Space lock */
921 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
922 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
924 /* Initialize AVL tree */
925 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
926 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
928 /* Lock PFN database */
929 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
931 /* Setup the PFN for the PDE base of this process */
932 PointerPte
= MiAddressToPte(PDE_BASE
);
933 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
934 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
936 /* Do the same for hyperspace */
937 PointerPde
= MiAddressToPde(HYPER_SPACE
);
938 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
939 MiInitializePfn(PageFrameNumber
, PointerPde
, TRUE
);
941 /* Release PFN lock */
942 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
944 /* Lock the VAD, ARM3-owned ranges away */
945 MiRosTakeOverPebTebRanges(Process
);
947 /* Check if there's a Section Object */
950 /* Determine the image file name and save it to EPROCESS */
951 FileName
= SectionObject
->FileObject
->FileName
;
952 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
955 /* Loop the file name*/
956 while (Source
> FileName
.Buffer
)
958 /* Make sure this isn't a backslash */
959 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
961 /* If so, stop it here */
967 /* Otherwise, keep going */
973 /* Copy the to the process and truncate it to 15 characters if necessary */
974 Destination
= Process
->ImageFileName
;
975 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
976 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
977 *Destination
= ANSI_NULL
;
979 /* Check if caller wants an audit name */
982 /* Setup the audit name */
983 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
986 if (!NT_SUCCESS(Status
))
994 /* Map the section */
995 Status
= MmMapViewOfSection(Section
,
1006 /* Save the pointer */
1007 Process
->SectionBaseAddress
= ImageBase
;
1010 /* Be nice and detach */
1013 /* Return status to caller */
1019 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1020 IN PULONG_PTR DirectoryTableBase
)
1022 /* Share the directory base with the idle process */
1023 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1024 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1026 /* Initialize the Addresss Space */
1027 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1028 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1029 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1030 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1031 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1034 Process
->HasAddressSpace
= TRUE
;//??
1035 return STATUS_SUCCESS
;
1040 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1042 /* Lock the VAD, ARM3-owned ranges away */
1043 MiRosTakeOverPebTebRanges(Process
);
1044 return STATUS_SUCCESS
;
1048 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1051 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1052 IN PEPROCESS Process
,
1053 OUT PULONG_PTR DirectoryTableBase
)
1056 PFN_NUMBER PdeIndex
, HyperIndex
;
1058 MMPTE TempPte
, PdePte
;
1062 /* No page colors yet */
1063 Process
->NextPageColor
= 0;
1065 /* Setup the hyperspace lock */
1066 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1068 /* Lock PFN database */
1069 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1071 /* Get a page for the PDE */
1072 PdeIndex
= MiRemoveAnyPage(0);
1073 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1074 MiZeroPhysicalPage(PdeIndex
);
1075 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1077 /* Get a page for hyperspace */
1078 HyperIndex
= MiRemoveAnyPage(0);
1079 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1080 MiZeroPhysicalPage(HyperIndex
);
1082 /* Switch to phase 1 initialization */
1083 ASSERT(Process
->AddressSpaceInitialized
== 0);
1084 Process
->AddressSpaceInitialized
= 1;
1086 /* Set the base directory pointers */
1087 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1088 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1090 /* Make sure we don't already have a page directory setup */
1091 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1093 /* Insert us into the Mm process list */
1094 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1096 /* Get a PTE to map the page directory */
1097 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1098 ASSERT(PointerPte
!= NULL
);
1101 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1106 /* Set it dirty and map it */
1107 PdePte
.u
.Hard
.Dirty
= TRUE
;
1108 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1110 /* Now get the page directory (which we'll double map, so call it a page table */
1111 SystemTable
= MiPteToAddress(PointerPte
);
1113 /* Copy all the kernel mappings */
1114 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1116 RtlCopyMemory(&SystemTable
[PdeOffset
],
1117 MiAddressToPde(MmSystemRangeStart
),
1118 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1120 /* Now write the PTE/PDE entry for hyperspace itself */
1121 TempPte
= ValidKernelPte
;
1122 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1123 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1124 SystemTable
[PdeOffset
] = TempPte
;
1128 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1130 /* Now do the x86 trick of making the PDE a page table itself */
1131 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1132 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1133 SystemTable
[PdeOffset
] = TempPte
;
1135 /* Let go of the system PTE */
1136 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1143 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1146 PMM_AVL_TABLE VadTree
;
1147 PETHREAD Thread
= PsGetCurrentThread();
1149 /* Lock the process address space from changes */
1150 MmLockAddressSpace(&Process
->Vm
);
1152 /* Enumerate the VADs */
1153 VadTree
= &Process
->VadRoot
;
1154 DPRINT("Cleaning up VADs: %d\n", VadTree
->NumberGenericTableElements
);
1155 while (VadTree
->NumberGenericTableElements
)
1157 /* Grab the current VAD */
1158 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1160 /* Lock the working set */
1161 MiLockProcessWorkingSet(Process
, Thread
);
1163 /* Remove this VAD from the tree */
1164 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1165 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1166 DPRINT("Moving on: %d\n", VadTree
->NumberGenericTableElements
);
1168 /* Only PEB/TEB VADs supported for now */
1169 ASSERT(Vad
->u
.VadFlags
.PrivateMemory
== 1);
1170 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1172 /* Release the working set */
1173 MiUnlockProcessWorkingSet(Process
, Thread
);
1175 /* Free the VAD memory */
1179 /* Release the address space */
1180 MmUnlockAddressSpace(&Process
->Vm
);
1183 /* SYSTEM CALLS ***************************************************************/
1187 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1188 IN OUT PULONG_PTR NumberOfPages
,
1189 IN OUT PULONG_PTR UserPfnArray
)
1192 return STATUS_NOT_IMPLEMENTED
;
1197 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1198 IN ULONG_PTR NumberOfPages
,
1199 IN OUT PULONG_PTR UserPfnArray
)
1202 return STATUS_NOT_IMPLEMENTED
;
1207 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1208 IN ULONG_PTR NumberOfPages
,
1209 IN OUT PULONG_PTR UserPfnArray
)
1212 return STATUS_NOT_IMPLEMENTED
;
1217 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1218 IN OUT PULONG_PTR NumberOfPages
,
1219 IN OUT PULONG_PTR UserPfnArray
)
1222 return STATUS_NOT_IMPLEMENTED
;