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 /* GLOBALS ********************************************************************/
21 ULONG MmProcessColorSeed
= 0x12345678;
23 /* PRIVATE FUNCTIONS **********************************************************/
27 MiRosTakeOverPebTebRanges(IN PEPROCESS Process
)
30 PMEMORY_AREA MemoryArea
;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
32 PVOID AllocatedBase
= (PVOID
)USER_SHARED_DATA
;
33 BoundaryAddressMultiple
.QuadPart
= 0;
35 Status
= MmCreateMemoryArea(&Process
->Vm
,
36 MEMORY_AREA_OWNED_BY_ARM3
,
38 ((ULONG_PTR
)MM_HIGHEST_USER_ADDRESS
- 1) -
39 (ULONG_PTR
)USER_SHARED_DATA
,
44 BoundaryAddressMultiple
);
45 ASSERT(NT_SUCCESS(Status
));
50 MiCreatePebOrTeb(IN PEPROCESS Process
,
54 PETHREAD Thread
= PsGetCurrentThread();
58 ULONG_PTR StartAddress
, EndAddress
;
59 LARGE_INTEGER CurrentTime
;
60 TABLE_SEARCH_RESULT Result
= TableFoundNode
;
61 PMMADDRESS_NODE Parent
;
64 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD_LONG
), 'ldaV');
65 if (!Vad
) return STATUS_NO_MEMORY
;
67 /* Setup the primary flags with the size, and make it commited, private, RW */
69 Vad
->u
.VadFlags
.CommitCharge
= BYTES_TO_PAGES(Size
);
70 Vad
->u
.VadFlags
.MemCommit
= TRUE
;
71 Vad
->u
.VadFlags
.PrivateMemory
= TRUE
;
72 Vad
->u
.VadFlags
.Protection
= MM_READWRITE
;
73 Vad
->u
.VadFlags
.NoChange
= TRUE
;
75 /* Setup the secondary flags to make it a secured, writable, long VAD */
76 Vad
->u2
.LongFlags2
= 0;
77 Vad
->u2
.VadFlags2
.OneSecured
= TRUE
;
78 Vad
->u2
.VadFlags2
.LongVad
= TRUE
;
79 Vad
->u2
.VadFlags2
.ReadOnly
= FALSE
;
81 /* Lock the process address space */
82 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
84 /* Check if this is a PEB creation */
85 if (Size
== sizeof(PEB
))
87 /* Start at the highest valid address */
88 StartAddress
= (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1;
90 /* Select the random coefficient */
91 KeQueryTickCount(&CurrentTime
);
92 CurrentTime
.LowPart
&= ((64 * _1KB
) >> PAGE_SHIFT
) - 1;
93 if (CurrentTime
.LowPart
<= 1) CurrentTime
.LowPart
= 2;
94 RandomCoeff
= CurrentTime
.LowPart
<< PAGE_SHIFT
;
96 /* Select the highest valid address minus the random coefficient */
97 StartAddress
-= RandomCoeff
;
98 EndAddress
= StartAddress
+ ROUND_TO_PAGES(Size
) - 1;
100 /* Try to find something below the random upper margin */
101 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
109 /* Check for success. TableFoundNode means nothing free. */
110 if (Result
== TableFoundNode
)
112 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
113 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
114 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1,
119 /* Bail out, if still nothing free was found */
120 if (Result
== TableFoundNode
) return STATUS_NO_MEMORY
;
123 /* Validate that it came from the VAD ranges */
124 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
126 /* Build the rest of the VAD now */
127 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
128 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
129 Vad
->u3
.Secured
.StartVpn
= *Base
;
130 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
131 Vad
->u1
.Parent
= NULL
;
133 /* FIXME: Should setup VAD bitmap */
134 Status
= STATUS_SUCCESS
;
136 /* Pretend as if we own the working set */
137 MiLockProcessWorkingSet(Process
, Thread
);
140 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
141 Process
->VadRoot
.NodeHint
= Vad
;
142 Vad
->ControlArea
= NULL
; // For Memory-Area hack
143 Vad
->FirstPrototypePte
= NULL
;
144 DPRINT("VAD: %p\n", Vad
);
145 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
146 MiInsertNode(&Process
->VadRoot
, (PVOID
)Vad
, Parent
, Result
);
148 /* Release the working set */
149 MiUnlockProcessWorkingSet(Process
, Thread
);
151 /* Release the address space lock */
152 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
154 /* Return the status */
160 MmDeleteTeb(IN PEPROCESS Process
,
164 PETHREAD Thread
= PsGetCurrentThread();
166 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
167 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
169 /* TEB is one page */
170 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
172 /* Attach to the process */
173 KeAttachProcess(&Process
->Pcb
);
175 /* Lock the process address space */
176 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
178 /* Find the VAD, make sure it's a TEB VAD */
179 Vad
= MiLocateAddress(Teb
);
180 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
182 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
184 /* Bug in the AVL code? */
185 DPRINT1("Corrupted VAD!\n");
189 /* Sanity checks for a valid TEB VAD */
190 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
191 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
192 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
193 ASSERT(Vad
->u2
.VadFlags2
.OneSecured
== TRUE
);
194 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
196 /* Lock the working set */
197 MiLockProcessWorkingSet(Process
, Thread
);
199 /* Remove this VAD from the tree */
200 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
201 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
203 /* Release the working set */
204 MiUnlockProcessWorkingSet(Process
, Thread
);
210 /* Release the address space lock */
211 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
219 MmDeleteKernelStack(IN PVOID StackBase
,
223 PFN_NUMBER StackPages
, PageFrameNumber
;//, PageTableFrameNumber;
224 PMMPFN Pfn1
;//, Pfn2;
229 // This should be the guard page, so decrement by one
231 PointerPte
= MiAddressToPte(StackBase
);
235 // Calculate pages used
237 StackPages
= BYTES_TO_PAGES(GuiStack
?
238 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
240 /* Acquire the PFN lock */
241 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
246 for (i
= 0; i
< StackPages
; i
++)
249 // Check if this is a valid PTE
251 if (PointerPte
->u
.Hard
.Valid
== 1)
253 /* Get the PTE's page */
254 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
255 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
256 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
257 /* Now get the page of the page table mapping it */
258 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
259 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
261 /* Remove a shared reference, since the page is going away */
262 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
264 /* Set the special pending delete marker */
265 MI_SET_PFN_DELETED(Pfn1
);
267 /* And now delete the actual stack page */
268 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
278 // We should be at the guard page now
280 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
282 /* Release the PFN lock */
283 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
288 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
293 MmCreateKernelStack(IN BOOLEAN GuiStack
,
296 PFN_NUMBER StackPtes
, StackPages
;
297 PMMPTE PointerPte
, StackPte
;
299 MMPTE TempPte
, InvalidPte
;
301 PFN_NUMBER PageFrameIndex
;
305 // Calculate pages needed
310 // We'll allocate 64KB stack, but only commit 12K
312 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
313 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
319 // We'll allocate 12K and that's it
321 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
322 StackPages
= StackPtes
;
326 // Reserve stack pages, plus a guard page
328 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
329 if (!StackPte
) return NULL
;
332 // Get the stack address
334 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
337 // Select the right PTE address where we actually start committing pages
339 PointerPte
= StackPte
;
340 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
341 KERNEL_LARGE_STACK_COMMIT
);
344 /* Setup the temporary invalid PTE */
345 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
347 /* Setup the template stack PTE */
348 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
351 // Acquire the PFN DB lock
353 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
356 // Loop each stack page
358 for (i
= 0; i
< StackPages
; i
++)
365 /* Get a page and write the current invalid PTE */
366 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
367 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
369 /* Initialize the PFN entry for this page */
370 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
372 /* Write the valid PTE */
373 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
374 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
378 // Release the PFN lock
380 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
383 // Return the stack address
390 MmGrowKernelStackEx(IN PVOID StackPointer
,
393 PKTHREAD Thread
= KeGetCurrentThread();
394 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
396 MMPTE TempPte
, InvalidPte
;
397 PFN_NUMBER PageFrameIndex
;
400 // Make sure the stack did not overflow
402 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
403 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
406 // Get the current stack limit
408 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
409 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
412 // Get the new one and make sure this isn't a retarded request
414 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
415 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
418 // Now make sure you're not going past the reserved space
420 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
421 KERNEL_LARGE_STACK_SIZE
));
422 if (NewLimitPte
< LastPte
)
427 DPRINT1("Thread wants too much stack\n");
428 return STATUS_STACK_OVERFLOW
;
432 // Calculate the number of new pages
436 /* Setup the temporary invalid PTE */
437 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
440 // Acquire the PFN DB lock
442 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
445 // Loop each stack page
447 while (LimitPte
>= NewLimitPte
)
449 /* Get a page and write the current invalid PTE */
450 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
451 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
453 /* Initialize the PFN entry for this page */
454 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
456 /* Setup the template stack PTE */
457 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
459 /* Write the valid PTE */
460 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
464 // Release the PFN lock
466 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
471 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
472 return STATUS_SUCCESS
;
477 MmGrowKernelStack(IN PVOID StackPointer
)
480 // Call the extended version
482 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
487 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
488 IN UCHAR MemoryPriority
)
493 // Check if we have less then 16MB of Physical Memory
495 if ((MmSystemSize
== MmSmallSystem
) &&
496 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
499 // Always use background priority
501 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
505 // Save the old priority and update it
507 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
508 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
511 // Return the old priority
518 MmGetSessionLocaleId(VOID
)
524 // Get the current process
526 Process
= PsGetCurrentProcess();
529 // Check if it's the Session Leader
531 if (Process
->Vm
.Flags
.SessionLeader
)
534 // Make sure it has a valid Session
536 if (Process
->Session
)
542 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
548 // Not a session leader, return the default
550 return PsDefaultThreadLocaleId
;
555 MmCreatePeb(IN PEPROCESS Process
,
556 IN PINITIAL_PEB InitialPeb
,
560 LARGE_INTEGER SectionOffset
;
562 PVOID TableBase
= NULL
;
563 PIMAGE_NT_HEADERS NtHeaders
;
564 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
566 USHORT Characteristics
;
567 KAFFINITY ProcessAffinityMask
= 0;
568 SectionOffset
.QuadPart
= (ULONGLONG
)0;
574 KeAttachProcess(&Process
->Pcb
);
579 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
580 ASSERT(NT_SUCCESS(Status
));
585 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
595 if (!NT_SUCCESS(Status
)) return Status
;
598 // Use SEH in case we can't load the PEB
603 // Initialize the PEB
605 RtlZeroMemory(Peb
, sizeof(PEB
));
610 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
611 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
612 Peb
->Mutant
= InitialPeb
->Mutant
;
613 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
618 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
619 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
620 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
623 // Default Version Data (could get changed below)
625 Peb
->OSMajorVersion
= NtMajorVersion
;
626 Peb
->OSMinorVersion
= NtMinorVersion
;
627 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
628 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
629 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
632 // Heap and Debug Data
634 Peb
->NumberOfProcessors
= KeNumberProcessors
;
635 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
636 Peb
->NtGlobalFlag
= NtGlobalFlag
;
637 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
638 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
639 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
640 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
641 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
642 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
644 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
645 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
650 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
652 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
658 _SEH2_YIELD(return _SEH2_GetExceptionCode());
663 // Use SEH in case we can't load the image
670 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
671 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
673 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
679 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
689 // Use SEH in case we can't load the headers
694 // Get the Image Config Data too
696 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
698 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
705 ProbeForRead(ImageConfigData
,
706 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
711 // Write subsystem data
713 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
714 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
715 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
718 // Check for version data
720 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
723 // Extract values and write them
725 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
726 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
727 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
728 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
732 // Process the image config data overrides if specfied
734 if (ImageConfigData
!= NULL
)
737 // Process CSD version override
739 if (ImageConfigData
->CSDVersion
)
744 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
748 // Process affinity mask ovverride
750 if (ImageConfigData
->ProcessAffinityMask
)
755 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
760 // Check if this is a UP image
761 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
764 // Force it to use CPU 0
766 Peb
->ImageProcessAffinityMask
= 0;
771 // Whatever was configured
773 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
782 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
788 // Detach from the Process
792 return STATUS_SUCCESS
;
797 MmCreateTeb(IN PEPROCESS Process
,
798 IN PCLIENT_ID ClientId
,
799 IN PINITIAL_TEB InitialTeb
,
803 NTSTATUS Status
= STATUS_SUCCESS
;
809 KeAttachProcess(&Process
->Pcb
);
814 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
815 ASSERT(NT_SUCCESS(Status
));
818 // Use SEH in case we can't load the TEB
823 // Initialize the PEB
825 RtlZeroMemory(Teb
, sizeof(TEB
));
830 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
831 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
834 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
836 Teb
->NtTib
.Version
= 30 << 8;
841 Teb
->ClientId
= *ClientId
;
842 Teb
->RealClientId
= *ClientId
;
843 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
844 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
847 // Check if we have a grandparent TEB
849 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
850 (InitialTeb
->PreviousStackLimit
== NULL
))
853 // Use initial TEB values
855 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
856 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
857 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
862 // Use grandparent TEB values
864 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
865 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
869 // Initialize the static unicode string
871 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
872 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
879 Status
= _SEH2_GetExceptionCode();
893 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
894 IN PEPROCESS ProcessClone OPTIONAL
,
895 IN PVOID Section OPTIONAL
,
897 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
899 NTSTATUS Status
= STATUS_SUCCESS
;
902 PROS_SECTION_OBJECT SectionObject
= Section
;
906 PFN_NUMBER PageFrameNumber
;
907 UNICODE_STRING FileName
;
912 /* We should have a PDE */
913 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
914 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
916 /* Attach to the process */
917 KeAttachProcess(&Process
->Pcb
);
919 /* The address space should now been in phase 1 or 0 */
920 ASSERT(Process
->AddressSpaceInitialized
<= 1);
921 Process
->AddressSpaceInitialized
= 2;
923 /* Initialize the Addresss Space lock */
924 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
925 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
927 /* Initialize AVL tree */
928 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
929 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
931 /* Lock PFN database */
932 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
934 /* Setup the PFN for the PDE base of this process */
935 PointerPte
= MiAddressToPte(PDE_BASE
);
936 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
937 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
939 /* Do the same for hyperspace */
940 PointerPde
= MiAddressToPde(HYPER_SPACE
);
941 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
942 MiInitializePfn(PageFrameNumber
, PointerPde
, TRUE
);
944 /* Release PFN lock */
945 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
947 /* Lock the VAD, ARM3-owned ranges away */
948 MiRosTakeOverPebTebRanges(Process
);
950 /* Check if there's a Section Object */
953 /* Determine the image file name and save it to EPROCESS */
954 FileName
= SectionObject
->FileObject
->FileName
;
955 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
958 /* Loop the file name*/
959 while (Source
> FileName
.Buffer
)
961 /* Make sure this isn't a backslash */
962 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
964 /* If so, stop it here */
970 /* Otherwise, keep going */
976 /* Copy the to the process and truncate it to 15 characters if necessary */
977 Destination
= Process
->ImageFileName
;
978 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
979 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
980 *Destination
= ANSI_NULL
;
982 /* Check if caller wants an audit name */
985 /* Setup the audit name */
986 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
989 if (!NT_SUCCESS(Status
))
997 /* Map the section */
998 Status
= MmMapViewOfSection(Section
,
1009 /* Save the pointer */
1010 Process
->SectionBaseAddress
= ImageBase
;
1013 /* Be nice and detach */
1016 /* Return status to caller */
1022 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1023 IN PULONG_PTR DirectoryTableBase
)
1025 /* Share the directory base with the idle process */
1026 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1027 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1029 /* Initialize the Addresss Space */
1030 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1031 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1032 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1033 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1034 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1037 Process
->HasAddressSpace
= TRUE
;//??
1038 return STATUS_SUCCESS
;
1043 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1045 /* Lock the VAD, ARM3-owned ranges away */
1046 MiRosTakeOverPebTebRanges(Process
);
1047 return STATUS_SUCCESS
;
1051 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1054 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1055 IN PEPROCESS Process
,
1056 OUT PULONG_PTR DirectoryTableBase
)
1059 PFN_NUMBER PdeIndex
, HyperIndex
;
1061 MMPTE TempPte
, PdePte
;
1066 /* Choose a process color */
1067 Process
->NextPageColor
= RtlRandom(&MmProcessColorSeed
);
1069 /* Setup the hyperspace lock */
1070 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1072 /* Lock PFN database */
1073 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1075 /* Get a zero page for the PDE, if possible */
1076 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1077 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1080 /* No zero pages, grab a free one */
1081 PdeIndex
= MiRemoveAnyPage(Color
);
1083 /* Zero it outside the PFN lock */
1084 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1085 MiZeroPhysicalPage(PdeIndex
);
1086 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1089 /* Get a zero page for hyperspace, if possible */
1090 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1091 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1094 /* No zero pages, grab a free one */
1095 HyperIndex
= MiRemoveAnyPage(Color
);
1097 /* Zero it outside the PFN lock */
1098 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1099 MiZeroPhysicalPage(HyperIndex
);
1103 /* Release the PFN lock */
1104 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1107 /* Switch to phase 1 initialization */
1108 ASSERT(Process
->AddressSpaceInitialized
== 0);
1109 Process
->AddressSpaceInitialized
= 1;
1111 /* Set the base directory pointers */
1112 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1113 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1115 /* Make sure we don't already have a page directory setup */
1116 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1118 /* Insert us into the Mm process list */
1119 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1121 /* Get a PTE to map the page directory */
1122 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1123 ASSERT(PointerPte
!= NULL
);
1126 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1131 /* Set it dirty and map it */
1132 PdePte
.u
.Hard
.Dirty
= TRUE
;
1133 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1135 /* Now get the page directory (which we'll double map, so call it a page table */
1136 SystemTable
= MiPteToAddress(PointerPte
);
1138 /* Copy all the kernel mappings */
1139 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1140 RtlCopyMemory(&SystemTable
[PdeOffset
],
1141 MiAddressToPde(MmSystemRangeStart
),
1142 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1144 /* Now write the PTE/PDE entry for hyperspace itself */
1145 TempPte
= ValidKernelPte
;
1146 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1147 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1148 SystemTable
[PdeOffset
] = TempPte
;
1152 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1154 /* Now do the x86 trick of making the PDE a page table itself */
1155 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1156 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1157 SystemTable
[PdeOffset
] = TempPte
;
1159 /* Let go of the system PTE */
1160 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1167 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1170 PMM_AVL_TABLE VadTree
;
1171 PETHREAD Thread
= PsGetCurrentThread();
1173 /* Only support this */
1174 ASSERT(Process
->AddressSpaceInitialized
== 2);
1176 /* Lock the process address space from changes */
1177 MmLockAddressSpace(&Process
->Vm
);
1179 /* VM is deleted now */
1180 Process
->VmDeleted
= TRUE
;
1182 /* Enumerate the VADs */
1183 VadTree
= &Process
->VadRoot
;
1184 while (VadTree
->NumberGenericTableElements
)
1186 /* Grab the current VAD */
1187 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1189 /* Lock the working set */
1190 MiLockProcessWorkingSet(Process
, Thread
);
1192 /* Remove this VAD from the tree */
1193 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1194 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1196 /* Only regular VADs supported for now */
1197 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1199 /* Check if this is a section VAD */
1200 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1202 /* Remove the view */
1203 MiRemoveMappedView(Process
, Vad
);
1207 /* Delete the addresses */
1208 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1209 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1212 /* Release the working set */
1213 MiUnlockProcessWorkingSet(Process
, Thread
);
1216 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1217 if (Vad
->u
.VadFlags
.Spare
== 1)
1219 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1220 Vad
->u
.VadFlags
.Spare
= 2;
1224 /* Free the VAD memory */
1228 /* Release the address space */
1229 MmUnlockAddressSpace(&Process
->Vm
);
1232 /* SYSTEM CALLS ***************************************************************/
1236 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1237 IN OUT PULONG_PTR NumberOfPages
,
1238 IN OUT PULONG_PTR UserPfnArray
)
1241 return STATUS_NOT_IMPLEMENTED
;
1246 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1247 IN ULONG_PTR NumberOfPages
,
1248 IN OUT PULONG_PTR UserPfnArray
)
1251 return STATUS_NOT_IMPLEMENTED
;
1256 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1257 IN ULONG_PTR NumberOfPages
,
1258 IN OUT PULONG_PTR UserPfnArray
)
1261 return STATUS_NOT_IMPLEMENTED
;
1266 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1267 IN OUT PULONG_PTR NumberOfPages
,
1268 IN OUT PULONG_PTR UserPfnArray
)
1271 return STATUS_NOT_IMPLEMENTED
;