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;
22 PMMWSL MmWorkingSetList
;
24 /* PRIVATE FUNCTIONS **********************************************************/
28 MiRosTakeOverPebTebRanges(IN PEPROCESS Process
)
31 PMEMORY_AREA MemoryArea
;
32 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
33 PVOID AllocatedBase
= (PVOID
)USER_SHARED_DATA
;
34 BoundaryAddressMultiple
.QuadPart
= 0;
36 Status
= MmCreateMemoryArea(&Process
->Vm
,
37 MEMORY_AREA_OWNED_BY_ARM3
,
39 ((ULONG_PTR
)MM_HIGHEST_USER_ADDRESS
- 1) -
40 (ULONG_PTR
)USER_SHARED_DATA
,
45 BoundaryAddressMultiple
);
46 ASSERT(NT_SUCCESS(Status
));
51 MiCreatePebOrTeb(IN PEPROCESS Process
,
55 PETHREAD Thread
= PsGetCurrentThread();
59 ULONG_PTR StartAddress
, EndAddress
;
60 LARGE_INTEGER CurrentTime
;
61 TABLE_SEARCH_RESULT Result
= TableFoundNode
;
62 PMMADDRESS_NODE Parent
;
65 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD_LONG
), 'ldaV');
66 if (!Vad
) return STATUS_NO_MEMORY
;
68 /* Setup the primary flags with the size, and make it commited, private, RW */
70 Vad
->u
.VadFlags
.CommitCharge
= BYTES_TO_PAGES(Size
);
71 Vad
->u
.VadFlags
.MemCommit
= TRUE
;
72 Vad
->u
.VadFlags
.PrivateMemory
= TRUE
;
73 Vad
->u
.VadFlags
.Protection
= MM_READWRITE
;
74 Vad
->u
.VadFlags
.NoChange
= TRUE
;
76 /* Setup the secondary flags to make it a secured, writable, long VAD */
77 Vad
->u2
.LongFlags2
= 0;
78 Vad
->u2
.VadFlags2
.OneSecured
= TRUE
;
79 Vad
->u2
.VadFlags2
.LongVad
= TRUE
;
80 Vad
->u2
.VadFlags2
.ReadOnly
= FALSE
;
82 /* Lock the process address space */
83 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
85 /* Check if this is a PEB creation */
86 if (Size
== sizeof(PEB
))
88 /* Start at the highest valid address */
89 StartAddress
= (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1;
91 /* Select the random coefficient */
92 KeQueryTickCount(&CurrentTime
);
93 CurrentTime
.LowPart
&= ((64 * _1KB
) >> PAGE_SHIFT
) - 1;
94 if (CurrentTime
.LowPart
<= 1) CurrentTime
.LowPart
= 2;
95 RandomCoeff
= CurrentTime
.LowPart
<< PAGE_SHIFT
;
97 /* Select the highest valid address minus the random coefficient */
98 StartAddress
-= RandomCoeff
;
99 EndAddress
= StartAddress
+ ROUND_TO_PAGES(Size
) - 1;
101 /* Try to find something below the random upper margin */
102 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
110 /* Check for success. TableFoundNode means nothing free. */
111 if (Result
== TableFoundNode
)
113 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
114 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
115 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1,
120 /* Bail out, if still nothing free was found */
121 if (Result
== TableFoundNode
) return STATUS_NO_MEMORY
;
124 /* Validate that it came from the VAD ranges */
125 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
127 /* Build the rest of the VAD now */
128 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
129 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
130 Vad
->u3
.Secured
.StartVpn
= *Base
;
131 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
132 Vad
->u1
.Parent
= NULL
;
134 /* FIXME: Should setup VAD bitmap */
135 Status
= STATUS_SUCCESS
;
137 /* Pretend as if we own the working set */
138 MiLockProcessWorkingSet(Process
, Thread
);
141 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
142 Process
->VadRoot
.NodeHint
= Vad
;
143 Vad
->ControlArea
= NULL
; // For Memory-Area hack
144 Vad
->FirstPrototypePte
= NULL
;
145 DPRINT("VAD: %p\n", Vad
);
146 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
147 MiInsertNode(&Process
->VadRoot
, (PVOID
)Vad
, Parent
, Result
);
149 /* Release the working set */
150 MiUnlockProcessWorkingSet(Process
, Thread
);
152 /* Release the address space lock */
153 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
155 /* Return the status */
161 MmDeleteTeb(IN PEPROCESS Process
,
165 PETHREAD Thread
= PsGetCurrentThread();
167 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
168 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
170 /* TEB is one page */
171 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
173 /* Attach to the process */
174 KeAttachProcess(&Process
->Pcb
);
176 /* Lock the process address space */
177 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
179 /* Find the VAD, make sure it's a TEB VAD */
180 Vad
= MiLocateAddress(Teb
);
181 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
183 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
185 /* Bug in the AVL code? */
186 DPRINT1("Corrupted VAD!\n");
190 /* Sanity checks for a valid TEB VAD */
191 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
192 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
193 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
194 ASSERT(Vad
->u2
.VadFlags2
.OneSecured
== TRUE
);
195 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
197 /* Lock the working set */
198 MiLockProcessWorkingSet(Process
, Thread
);
200 /* Remove this VAD from the tree */
201 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
202 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
204 /* Release the working set */
205 MiUnlockProcessWorkingSet(Process
, Thread
);
211 /* Release the address space lock */
212 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
220 MmDeleteKernelStack(IN PVOID StackBase
,
224 PFN_NUMBER StackPages
, PageFrameNumber
;//, PageTableFrameNumber;
225 PMMPFN Pfn1
;//, Pfn2;
230 // This should be the guard page, so decrement by one
232 PointerPte
= MiAddressToPte(StackBase
);
236 // Calculate pages used
238 StackPages
= BYTES_TO_PAGES(GuiStack
?
239 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
241 /* Acquire the PFN lock */
242 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
247 for (i
= 0; i
< StackPages
; i
++)
250 // Check if this is a valid PTE
252 if (PointerPte
->u
.Hard
.Valid
== 1)
254 /* Get the PTE's page */
255 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
256 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
257 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
258 /* Now get the page of the page table mapping it */
259 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
260 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
262 /* Remove a shared reference, since the page is going away */
263 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
265 /* Set the special pending delete marker */
266 MI_SET_PFN_DELETED(Pfn1
);
268 /* And now delete the actual stack page */
269 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
279 // We should be at the guard page now
281 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
283 /* Release the PFN lock */
284 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
289 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
294 MmCreateKernelStack(IN BOOLEAN GuiStack
,
297 PFN_NUMBER StackPtes
, StackPages
;
298 PMMPTE PointerPte
, StackPte
;
300 MMPTE TempPte
, InvalidPte
;
302 PFN_NUMBER PageFrameIndex
;
306 // Calculate pages needed
311 // We'll allocate 64KB stack, but only commit 12K
313 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
314 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
320 // We'll allocate 12K and that's it
322 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
323 StackPages
= StackPtes
;
327 // Reserve stack pages, plus a guard page
329 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
330 if (!StackPte
) return NULL
;
333 // Get the stack address
335 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
338 // Select the right PTE address where we actually start committing pages
340 PointerPte
= StackPte
;
341 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
342 KERNEL_LARGE_STACK_COMMIT
);
345 /* Setup the temporary invalid PTE */
346 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
348 /* Setup the template stack PTE */
349 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
352 // Acquire the PFN DB lock
354 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
357 // Loop each stack page
359 for (i
= 0; i
< StackPages
; i
++)
366 /* Get a page and write the current invalid PTE */
367 MI_SET_USAGE(MI_USAGE_KERNEL_STACK
);
368 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
369 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
370 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
372 /* Initialize the PFN entry for this page */
373 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
375 /* Write the valid PTE */
376 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
377 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
381 // Release the PFN lock
383 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
386 // Return the stack address
393 MmGrowKernelStackEx(IN PVOID StackPointer
,
396 PKTHREAD Thread
= KeGetCurrentThread();
397 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
399 MMPTE TempPte
, InvalidPte
;
400 PFN_NUMBER PageFrameIndex
;
403 // Make sure the stack did not overflow
405 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
406 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
409 // Get the current stack limit
411 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
412 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
415 // Get the new one and make sure this isn't a retarded request
417 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
418 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
421 // Now make sure you're not going past the reserved space
423 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
424 KERNEL_LARGE_STACK_SIZE
));
425 if (NewLimitPte
< LastPte
)
430 DPRINT1("Thread wants too much stack\n");
431 return STATUS_STACK_OVERFLOW
;
435 // Calculate the number of new pages
439 /* Setup the temporary invalid PTE */
440 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
443 // Acquire the PFN DB lock
445 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
448 // Loop each stack page
450 while (LimitPte
>= NewLimitPte
)
452 /* Get a page and write the current invalid PTE */
453 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION
);
454 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
455 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
456 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
458 /* Initialize the PFN entry for this page */
459 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
461 /* Setup the template stack PTE */
462 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
464 /* Write the valid PTE */
465 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
469 // Release the PFN lock
471 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
476 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
477 return STATUS_SUCCESS
;
482 MmGrowKernelStack(IN PVOID StackPointer
)
485 // Call the extended version
487 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
492 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
493 IN UCHAR MemoryPriority
)
498 // Check if we have less then 16MB of Physical Memory
500 if ((MmSystemSize
== MmSmallSystem
) &&
501 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
504 // Always use background priority
506 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
510 // Save the old priority and update it
512 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
513 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
516 // Return the old priority
523 MmGetSessionLocaleId(VOID
)
529 // Get the current process
531 Process
= PsGetCurrentProcess();
534 // Check if it's the Session Leader
536 if (Process
->Vm
.Flags
.SessionLeader
)
539 // Make sure it has a valid Session
541 if (Process
->Session
)
547 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
553 // Not a session leader, return the default
555 return PsDefaultThreadLocaleId
;
560 MmCreatePeb(IN PEPROCESS Process
,
561 IN PINITIAL_PEB InitialPeb
,
565 LARGE_INTEGER SectionOffset
;
567 PVOID TableBase
= NULL
;
568 PIMAGE_NT_HEADERS NtHeaders
;
569 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
571 USHORT Characteristics
;
572 KAFFINITY ProcessAffinityMask
= 0;
573 SectionOffset
.QuadPart
= (ULONGLONG
)0;
579 KeAttachProcess(&Process
->Pcb
);
584 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
585 ASSERT(NT_SUCCESS(Status
));
590 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
600 if (!NT_SUCCESS(Status
)) return Status
;
603 // Use SEH in case we can't load the PEB
608 // Initialize the PEB
610 RtlZeroMemory(Peb
, sizeof(PEB
));
615 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
616 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
617 Peb
->Mutant
= InitialPeb
->Mutant
;
618 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
623 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
624 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
625 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
628 // Default Version Data (could get changed below)
630 Peb
->OSMajorVersion
= NtMajorVersion
;
631 Peb
->OSMinorVersion
= NtMinorVersion
;
632 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
633 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
634 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
637 // Heap and Debug Data
639 Peb
->NumberOfProcessors
= KeNumberProcessors
;
640 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
641 Peb
->NtGlobalFlag
= NtGlobalFlag
;
642 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
643 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
644 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
645 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
646 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
647 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
649 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
650 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
655 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
657 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
663 _SEH2_YIELD(return _SEH2_GetExceptionCode());
668 // Use SEH in case we can't load the image
675 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
676 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
678 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
684 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
694 // Use SEH in case we can't load the headers
699 // Get the Image Config Data too
701 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
703 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
710 ProbeForRead(ImageConfigData
,
711 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
716 // Write subsystem data
718 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
719 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
720 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
723 // Check for version data
725 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
728 // Extract values and write them
730 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
731 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
732 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
733 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
737 // Process the image config data overrides if specfied
739 if (ImageConfigData
!= NULL
)
742 // Process CSD version override
744 if (ImageConfigData
->CSDVersion
)
749 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
753 // Process affinity mask ovverride
755 if (ImageConfigData
->ProcessAffinityMask
)
760 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
765 // Check if this is a UP image
766 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
769 // Force it to use CPU 0
771 Peb
->ImageProcessAffinityMask
= 0;
776 // Whatever was configured
778 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
781 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
787 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
793 // Detach from the Process
797 return STATUS_SUCCESS
;
802 MmCreateTeb(IN PEPROCESS Process
,
803 IN PCLIENT_ID ClientId
,
804 IN PINITIAL_TEB InitialTeb
,
808 NTSTATUS Status
= STATUS_SUCCESS
;
814 KeAttachProcess(&Process
->Pcb
);
819 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
820 ASSERT(NT_SUCCESS(Status
));
823 // Use SEH in case we can't load the TEB
828 // Initialize the PEB
830 RtlZeroMemory(Teb
, sizeof(TEB
));
835 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
836 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
839 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
841 Teb
->NtTib
.Version
= 30 << 8;
846 Teb
->ClientId
= *ClientId
;
847 Teb
->RealClientId
= *ClientId
;
848 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
849 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
852 // Check if we have a grandparent TEB
854 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
855 (InitialTeb
->PreviousStackLimit
== NULL
))
858 // Use initial TEB values
860 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
861 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
862 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
867 // Use grandparent TEB values
869 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
870 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
874 // Initialize the static unicode string
876 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
877 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
879 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
884 Status
= _SEH2_GetExceptionCode();
898 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess
)
902 /* Setup some bogus list data */
903 MmWorkingSetList
->LastEntry
= CurrentProcess
->Vm
.MinimumWorkingSetSize
;
904 MmWorkingSetList
->HashTable
= NULL
;
905 MmWorkingSetList
->HashTableSize
= 0;
906 MmWorkingSetList
->NumberOfImageWaiters
= 0;
907 MmWorkingSetList
->Wsle
= (PVOID
)0xDEADBABE;
908 MmWorkingSetList
->VadBitMapHint
= 1;
909 MmWorkingSetList
->HashTableStart
= (PVOID
)0xBADAB00B;
910 MmWorkingSetList
->HighestPermittedHashAddress
= (PVOID
)0xCAFEBABE;
911 MmWorkingSetList
->FirstFree
= 1;
912 MmWorkingSetList
->FirstDynamic
= 2;
913 MmWorkingSetList
->NextSlot
= 3;
914 MmWorkingSetList
->LastInitializedWsle
= 4;
916 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
917 Pfn1
= MiGetPfnEntry(MiAddressToPte(PDE_BASE
)->u
.Hard
.PageFrameNumber
);
918 ASSERT(Pfn1
->u4
.PteFrame
== MiGetPfnEntryIndex(Pfn1
));
919 Pfn1
->u1
.Event
= (PKEVENT
)CurrentProcess
;
924 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
925 IN PEPROCESS ProcessClone OPTIONAL
,
926 IN PVOID Section OPTIONAL
,
928 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
930 NTSTATUS Status
= STATUS_SUCCESS
;
933 PROS_SECTION_OBJECT SectionObject
= Section
;
937 PFN_NUMBER PageFrameNumber
;
938 UNICODE_STRING FileName
;
944 /* We should have a PDE */
945 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
946 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
948 /* Attach to the process */
949 KeAttachProcess(&Process
->Pcb
);
951 /* The address space should now been in phase 1 or 0 */
952 ASSERT(Process
->AddressSpaceInitialized
<= 1);
953 Process
->AddressSpaceInitialized
= 2;
955 /* Initialize the Addresss Space lock */
956 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
957 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
959 /* Initialize AVL tree */
960 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
961 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
963 /* Lock PFN database */
964 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
966 /* Setup the PFN for the PDE base of this process */
967 PointerPte
= MiAddressToPte(PDE_BASE
);
968 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
969 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
971 /* Do the same for hyperspace */
972 PointerPde
= MiAddressToPde(HYPER_SPACE
);
973 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
974 MiInitializePfn(PageFrameNumber
, PointerPde
, TRUE
);
976 /* Setup the PFN for the PTE for the working set */
977 PointerPte
= MiAddressToPte(MI_WORKING_SET_LIST
);
978 MI_MAKE_HARDWARE_PTE(&TempPte
, PointerPte
, MM_READWRITE
, 0);
979 ASSERT(PointerPte
->u
.Long
!= 0);
980 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
981 MI_WRITE_INVALID_PTE(PointerPte
, DemandZeroPte
);
982 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
983 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameNumber
;
984 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
986 /* Now initialize the working set list */
987 MiInitializeWorkingSetList(Process
);
990 ASSERT(Process
->PhysicalVadRoot
== NULL
);
992 /* Release PFN lock */
993 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
995 /* Lock the VAD, ARM3-owned ranges away */
996 MiRosTakeOverPebTebRanges(Process
);
998 /* Check if there's a Section Object */
1001 /* Determine the image file name and save it to EPROCESS */
1002 FileName
= SectionObject
->FileObject
->FileName
;
1003 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
1004 if (FileName
.Buffer
)
1006 /* Loop the file name*/
1007 while (Source
> FileName
.Buffer
)
1009 /* Make sure this isn't a backslash */
1010 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
1012 /* If so, stop it here */
1018 /* Otherwise, keep going */
1024 /* Copy the to the process and truncate it to 15 characters if necessary */
1025 Destination
= Process
->ImageFileName
;
1026 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
1027 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
1028 *Destination
= ANSI_NULL
;
1030 /* Check if caller wants an audit name */
1033 /* Setup the audit name */
1034 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
1037 if (!NT_SUCCESS(Status
))
1045 /* Map the section */
1046 Status
= MmMapViewOfSection(Section
,
1057 /* Save the pointer */
1058 Process
->SectionBaseAddress
= ImageBase
;
1061 /* Be nice and detach */
1064 /* Return status to caller */
1071 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1072 IN PULONG_PTR DirectoryTableBase
)
1074 /* Share the directory base with the idle process */
1075 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1076 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1078 /* Initialize the Addresss Space */
1079 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1080 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1081 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1082 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1083 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1086 Process
->HasAddressSpace
= TRUE
;//??
1087 return STATUS_SUCCESS
;
1093 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1095 /* Lock the VAD, ARM3-owned ranges away */
1096 MiRosTakeOverPebTebRanges(Process
);
1097 return STATUS_SUCCESS
;
1101 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1104 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1105 IN PEPROCESS Process
,
1106 OUT PULONG_PTR DirectoryTableBase
)
1109 PFN_NUMBER PdeIndex
, HyperIndex
, WsListIndex
;
1111 MMPTE TempPte
, PdePte
;
1113 PMMPTE SystemTable
, HyperTable
;
1117 /* Choose a process color */
1118 Process
->NextPageColor
= RtlRandom(&MmProcessColorSeed
);
1120 /* Setup the hyperspace lock */
1121 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1123 /* Lock PFN database */
1124 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1126 /* Get a zero page for the PDE, if possible */
1127 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1128 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1129 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1132 /* No zero pages, grab a free one */
1133 PdeIndex
= MiRemoveAnyPage(Color
);
1135 /* Zero it outside the PFN lock */
1136 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1137 MiZeroPhysicalPage(PdeIndex
);
1138 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1141 /* Get a zero page for hyperspace, if possible */
1142 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1143 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1144 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1147 /* No zero pages, grab a free one */
1148 HyperIndex
= MiRemoveAnyPage(Color
);
1150 /* Zero it outside the PFN lock */
1151 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1152 MiZeroPhysicalPage(HyperIndex
);
1153 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1156 /* Get a zero page for the woring set list, if possible */
1157 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
1158 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1159 WsListIndex
= MiRemoveZeroPageSafe(Color
);
1162 /* No zero pages, grab a free one */
1163 WsListIndex
= MiRemoveAnyPage(Color
);
1165 /* Zero it outside the PFN lock */
1166 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1167 MiZeroPhysicalPage(WsListIndex
);
1171 /* Release the PFN lock */
1172 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1175 /* Switch to phase 1 initialization */
1176 ASSERT(Process
->AddressSpaceInitialized
== 0);
1177 Process
->AddressSpaceInitialized
= 1;
1179 /* Set the base directory pointers */
1180 Process
->WorkingSetPage
= WsListIndex
;
1181 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1182 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1184 /* Make sure we don't already have a page directory setup */
1185 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1187 /* Get a PTE to map hyperspace */
1188 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1189 ASSERT(PointerPte
!= NULL
);
1192 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1197 /* Set it dirty and map it */
1198 PdePte
.u
.Hard
.Dirty
= TRUE
;
1199 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1201 /* Now get hyperspace's page table */
1202 HyperTable
= MiPteToAddress(PointerPte
);
1204 /* Now write the PTE/PDE entry for the working set list index itself */
1205 TempPte
= ValidKernelPte
;
1206 TempPte
.u
.Hard
.PageFrameNumber
= WsListIndex
;
1207 PdeOffset
= MiAddressToPteOffset(MmWorkingSetList
);
1208 HyperTable
[PdeOffset
] = TempPte
;
1210 /* Let go of the system PTE */
1211 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1213 /* Save the PTE address of the page directory itself */
1214 Pfn1
= MiGetPfnEntry(PdeIndex
);
1215 Pfn1
->PteAddress
= (PMMPTE
)PDE_BASE
;
1217 /* Insert us into the Mm process list */
1218 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1220 /* Get a PTE to map the page directory */
1221 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1222 ASSERT(PointerPte
!= NULL
);
1225 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1230 /* Set it dirty and map it */
1231 PdePte
.u
.Hard
.Dirty
= TRUE
;
1232 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1234 /* Now get the page directory (which we'll double map, so call it a page table */
1235 SystemTable
= MiPteToAddress(PointerPte
);
1237 /* Copy all the kernel mappings */
1238 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1239 RtlCopyMemory(&SystemTable
[PdeOffset
],
1240 MiAddressToPde(MmSystemRangeStart
),
1241 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1243 /* Now write the PTE/PDE entry for hyperspace itself */
1244 TempPte
= ValidKernelPte
;
1245 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1246 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1247 SystemTable
[PdeOffset
] = TempPte
;
1251 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1253 /* Now do the x86 trick of making the PDE a page table itself */
1254 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1255 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1256 SystemTable
[PdeOffset
] = TempPte
;
1258 /* Let go of the system PTE */
1259 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1266 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1269 PMM_AVL_TABLE VadTree
;
1270 PETHREAD Thread
= PsGetCurrentThread();
1272 /* Only support this */
1273 ASSERT(Process
->AddressSpaceInitialized
== 2);
1275 /* Lock the process address space from changes */
1276 MmLockAddressSpace(&Process
->Vm
);
1278 /* VM is deleted now */
1279 Process
->VmDeleted
= TRUE
;
1281 /* Enumerate the VADs */
1282 VadTree
= &Process
->VadRoot
;
1283 while (VadTree
->NumberGenericTableElements
)
1285 /* Grab the current VAD */
1286 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1288 /* Lock the working set */
1289 MiLockProcessWorkingSet(Process
, Thread
);
1291 /* Remove this VAD from the tree */
1292 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1293 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1295 /* Only regular VADs supported for now */
1296 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1298 /* Check if this is a section VAD */
1299 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1301 /* Remove the view */
1302 MiRemoveMappedView(Process
, Vad
);
1306 /* Delete the addresses */
1307 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1308 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1311 /* Release the working set */
1312 MiUnlockProcessWorkingSet(Process
, Thread
);
1315 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1316 if (Vad
->u
.VadFlags
.Spare
== 1)
1318 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1319 Vad
->u
.VadFlags
.Spare
= 2;
1323 /* Free the VAD memory */
1327 /* Release the address space */
1328 MmUnlockAddressSpace(&Process
->Vm
);
1331 /* SYSTEM CALLS ***************************************************************/
1335 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1336 IN OUT PULONG_PTR NumberOfPages
,
1337 IN OUT PULONG_PTR UserPfnArray
)
1340 return STATUS_NOT_IMPLEMENTED
;
1345 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1346 IN ULONG_PTR NumberOfPages
,
1347 IN OUT PULONG_PTR UserPfnArray
)
1350 return STATUS_NOT_IMPLEMENTED
;
1355 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1356 IN ULONG_PTR NumberOfPages
,
1357 IN OUT PULONG_PTR UserPfnArray
)
1360 return STATUS_NOT_IMPLEMENTED
;
1365 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1366 IN OUT PULONG_PTR NumberOfPages
,
1367 IN OUT PULONG_PTR UserPfnArray
)
1370 return STATUS_NOT_IMPLEMENTED
;