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 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
18 /* GLOBALS ********************************************************************/
20 ULONG MmProcessColorSeed
= 0x12345678;
21 PMMWSL MmWorkingSetList
;
22 ULONG MmMaximumDeadKernelStacks
= 5;
23 SLIST_HEADER MmDeadStackSListHead
;
25 /* PRIVATE FUNCTIONS **********************************************************/
29 MiRosTakeOverSharedUserPage(IN PEPROCESS Process
)
32 PMEMORY_AREA MemoryArea
;
33 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
34 PVOID AllocatedBase
= (PVOID
)MM_SHARED_USER_DATA_VA
;
35 BoundaryAddressMultiple
.QuadPart
= 0;
37 Status
= MmCreateMemoryArea(&Process
->Vm
,
38 MEMORY_AREA_OWNED_BY_ARM3
,
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 /* Delete the pages */
205 MiDeleteVirtualAddresses((ULONG_PTR
)Teb
, TebEnd
, NULL
);
207 /* Release the working set */
208 MiUnlockProcessWorkingSet(Process
, Thread
);
214 /* Release the address space lock */
215 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
223 MmDeleteKernelStack(IN PVOID StackBase
,
227 PFN_NUMBER PageFrameNumber
, PageTableFrameNumber
;
228 PFN_COUNT StackPages
;
234 // This should be the guard page, so decrement by one
236 PointerPte
= MiAddressToPte(StackBase
);
240 // If this is a small stack, just push the stack onto the dead stack S-LIST
244 if (ExQueryDepthSList(&MmDeadStackSListHead
) < MmMaximumDeadKernelStacks
)
246 Pfn1
= MiGetPfnEntry(PointerPte
->u
.Hard
.PageFrameNumber
);
247 InterlockedPushEntrySList(&MmDeadStackSListHead
,
248 (PSLIST_ENTRY
)&Pfn1
->u1
.NextStackPfn
);
254 // Calculate pages used
256 StackPages
= BYTES_TO_PAGES(GuiStack
?
257 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
259 /* Acquire the PFN lock */
260 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
265 for (i
= 0; i
< StackPages
; i
++)
268 // Check if this is a valid PTE
270 if (PointerPte
->u
.Hard
.Valid
== 1)
272 /* Get the PTE's page */
273 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
274 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
276 /* Now get the page of the page table mapping it */
277 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
278 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
280 /* Remove a shared reference, since the page is going away */
281 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
283 /* Set the special pending delete marker */
284 MI_SET_PFN_DELETED(Pfn1
);
286 /* And now delete the actual stack page */
287 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
297 // We should be at the guard page now
299 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
301 /* Release the PFN lock */
302 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
307 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
312 MmCreateKernelStack(IN BOOLEAN GuiStack
,
315 PFN_COUNT StackPtes
, StackPages
;
316 PMMPTE PointerPte
, StackPte
;
318 MMPTE TempPte
, InvalidPte
;
320 PFN_NUMBER PageFrameIndex
;
325 // Calculate pages needed
330 // We'll allocate 64KB stack, but only commit 12K
332 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
333 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
339 // If the dead stack S-LIST has a stack on it, use it instead of allocating
340 // new system PTEs for this stack
342 if (ExQueryDepthSList(&MmDeadStackSListHead
))
344 Pfn1
= (PMMPFN
)InterlockedPopEntrySList(&MmDeadStackSListHead
);
347 PointerPte
= Pfn1
->PteAddress
;
348 BaseAddress
= MiPteToAddress(++PointerPte
);
354 // We'll allocate 12K and that's it
356 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
357 StackPages
= StackPtes
;
361 // Reserve stack pages, plus a guard page
363 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
364 if (!StackPte
) return NULL
;
367 // Get the stack address
369 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
372 // Select the right PTE address where we actually start committing pages
374 PointerPte
= StackPte
;
375 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
376 KERNEL_LARGE_STACK_COMMIT
);
379 /* Setup the temporary invalid PTE */
380 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
382 /* Setup the template stack PTE */
383 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
386 // Acquire the PFN DB lock
388 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
391 // Loop each stack page
393 for (i
= 0; i
< StackPages
; i
++)
400 /* Get a page and write the current invalid PTE */
401 MI_SET_USAGE(MI_USAGE_KERNEL_STACK
);
402 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
403 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
404 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
406 /* Initialize the PFN entry for this page */
407 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
409 /* Write the valid PTE */
410 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
411 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
415 // Release the PFN lock
417 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
420 // Return the stack address
427 MmGrowKernelStackEx(IN PVOID StackPointer
,
430 PKTHREAD Thread
= KeGetCurrentThread();
431 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
433 MMPTE TempPte
, InvalidPte
;
434 PFN_NUMBER PageFrameIndex
;
437 // Make sure the stack did not overflow
439 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
440 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
443 // Get the current stack limit
445 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
446 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
449 // Get the new one and make sure this isn't a retarded request
451 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
452 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
455 // Now make sure you're not going past the reserved space
457 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
458 KERNEL_LARGE_STACK_SIZE
));
459 if (NewLimitPte
< LastPte
)
464 DPRINT1("Thread wants too much stack\n");
465 return STATUS_STACK_OVERFLOW
;
469 // Calculate the number of new pages
473 /* Setup the temporary invalid PTE */
474 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
477 // Acquire the PFN DB lock
479 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
482 // Loop each stack page
484 while (LimitPte
>= NewLimitPte
)
486 /* Get a page and write the current invalid PTE */
487 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION
);
488 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
489 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
490 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
492 /* Initialize the PFN entry for this page */
493 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
495 /* Setup the template stack PTE */
496 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
498 /* Write the valid PTE */
499 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
503 // Release the PFN lock
505 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
510 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
511 return STATUS_SUCCESS
;
516 MmGrowKernelStack(IN PVOID StackPointer
)
519 // Call the extended version
521 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
526 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
527 IN UCHAR MemoryPriority
)
532 // Check if we have less then 16MB of Physical Memory
534 if ((MmSystemSize
== MmSmallSystem
) &&
535 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
538 // Always use background priority
540 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
544 // Save the old priority and update it
546 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
547 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
550 // Return the old priority
557 MmGetSessionLocaleId(VOID
)
563 // Get the current process
565 Process
= PsGetCurrentProcess();
568 // Check if it's the Session Leader
570 if (Process
->Vm
.Flags
.SessionLeader
)
573 // Make sure it has a valid Session
575 if (Process
->Session
)
581 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
587 // Not a session leader, return the default
589 return PsDefaultThreadLocaleId
;
594 MmCreatePeb(IN PEPROCESS Process
,
595 IN PINITIAL_PEB InitialPeb
,
599 LARGE_INTEGER SectionOffset
;
601 PVOID TableBase
= NULL
;
602 PIMAGE_NT_HEADERS NtHeaders
;
603 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
605 USHORT Characteristics
;
606 KAFFINITY ProcessAffinityMask
= 0;
607 SectionOffset
.QuadPart
= (ULONGLONG
)0;
613 KeAttachProcess(&Process
->Pcb
);
618 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
628 DPRINT("NLS Tables at: %p\n", TableBase
);
629 if (!NT_SUCCESS(Status
))
631 /* Cleanup and exit */
639 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
640 DPRINT("PEB at: %p\n", Peb
);
641 if (!NT_SUCCESS(Status
))
643 /* Cleanup and exit */
649 // Use SEH in case we can't load the PEB
654 // Initialize the PEB
656 RtlZeroMemory(Peb
, sizeof(PEB
));
661 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
662 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
663 Peb
->Mutant
= InitialPeb
->Mutant
;
664 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
669 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
670 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
671 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
674 // Default Version Data (could get changed below)
676 Peb
->OSMajorVersion
= NtMajorVersion
;
677 Peb
->OSMinorVersion
= NtMinorVersion
;
678 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
679 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
680 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
683 // Heap and Debug Data
685 Peb
->NumberOfProcessors
= KeNumberProcessors
;
686 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
);
687 Peb
->NtGlobalFlag
= NtGlobalFlag
;
688 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
689 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
690 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
691 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
692 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
693 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
695 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
696 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
701 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
709 _SEH2_YIELD(return _SEH2_GetExceptionCode());
714 // Use SEH in case we can't load the image
721 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
722 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
730 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
740 // Use SEH in case we can't load the headers
745 // Get the Image Config Data too
747 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
749 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
756 ProbeForRead(ImageConfigData
,
757 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
762 // Write subsystem data
764 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
765 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
766 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
769 // Check for version data
771 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
774 // Extract values and write them
776 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
777 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
778 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
779 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
781 /* Process CSD version override */
782 if ((ImageConfigData
) && (ImageConfigData
->CSDVersion
))
784 /* Take the value from the image configuration directory */
785 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
789 /* Process optional process affinity mask override */
790 if ((ImageConfigData
) && (ImageConfigData
->ProcessAffinityMask
))
792 /* Take the value from the image configuration directory */
793 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
797 // Check if this is a UP image
798 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
801 // Force it to use CPU 0
803 /* FIXME: this should use the MmRotatingUniprocessorNumber */
804 Peb
->ImageProcessAffinityMask
= 0;
809 // Whatever was configured
811 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
820 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
826 // Detach from the Process
830 return STATUS_SUCCESS
;
835 MmCreateTeb(IN PEPROCESS Process
,
836 IN PCLIENT_ID ClientId
,
837 IN PINITIAL_TEB InitialTeb
,
841 NTSTATUS Status
= STATUS_SUCCESS
;
847 KeAttachProcess(&Process
->Pcb
);
852 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
853 ASSERT(NT_SUCCESS(Status
));
856 // Use SEH in case we can't load the TEB
861 // Initialize the PEB
863 RtlZeroMemory(Teb
, sizeof(TEB
));
869 Teb
->NtTib
.ExceptionList
= NULL
;
871 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
873 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
876 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
878 Teb
->NtTib
.Version
= 30 << 8;
883 Teb
->ClientId
= *ClientId
;
884 Teb
->RealClientId
= *ClientId
;
885 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
886 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
889 // Check if we have a grandparent TEB
891 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
892 (InitialTeb
->PreviousStackLimit
== NULL
))
895 // Use initial TEB values
897 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
898 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
899 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
904 // Use grandparent TEB values
906 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
907 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
911 // Initialize the static unicode string
913 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
914 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
921 Status
= _SEH2_GetExceptionCode();
935 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess
)
941 /* Setup some bogus list data */
942 MmWorkingSetList
->LastEntry
= CurrentProcess
->Vm
.MinimumWorkingSetSize
;
943 MmWorkingSetList
->HashTable
= NULL
;
944 MmWorkingSetList
->HashTableSize
= 0;
945 MmWorkingSetList
->NumberOfImageWaiters
= 0;
946 MmWorkingSetList
->Wsle
= (PVOID
)0xDEADBABE;
947 MmWorkingSetList
->VadBitMapHint
= 1;
948 MmWorkingSetList
->HashTableStart
= (PVOID
)0xBADAB00B;
949 MmWorkingSetList
->HighestPermittedHashAddress
= (PVOID
)0xCAFEBABE;
950 MmWorkingSetList
->FirstFree
= 1;
951 MmWorkingSetList
->FirstDynamic
= 2;
952 MmWorkingSetList
->NextSlot
= 3;
953 MmWorkingSetList
->LastInitializedWsle
= 4;
955 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
956 Pfn1
= MiGetPfnEntry(CurrentProcess
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
);
957 ASSERT(Pfn1
->u4
.PteFrame
== MiGetPfnEntryIndex(Pfn1
));
958 Pfn1
->u1
.Event
= (PKEVENT
)CurrentProcess
;
960 /* Map the process working set in kernel space */
961 sysPte
= MiReserveSystemPtes(1, SystemPteSpace
);
962 MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte
, sysPte
, MM_READWRITE
, CurrentProcess
->WorkingSetPage
);
963 MI_WRITE_VALID_PTE(sysPte
, tempPte
);
964 CurrentProcess
->Vm
.VmWorkingSetList
= MiPteToAddress(sysPte
);
969 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
970 IN PEPROCESS ProcessClone OPTIONAL
,
971 IN PVOID Section OPTIONAL
,
973 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
975 NTSTATUS Status
= STATUS_SUCCESS
;
978 PROS_SECTION_OBJECT SectionObject
= Section
;
982 PFN_NUMBER PageFrameNumber
;
983 UNICODE_STRING FileName
;
989 /* We should have a PDE */
990 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
991 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
993 /* Attach to the process */
994 KeAttachProcess(&Process
->Pcb
);
996 /* The address space should now been in phase 1 or 0 */
997 ASSERT(Process
->AddressSpaceInitialized
<= 1);
998 Process
->AddressSpaceInitialized
= 2;
1000 /* Initialize the Addresss Space lock */
1001 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1002 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1004 /* Initialize AVL tree */
1005 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1006 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1008 /* Lock PFN database */
1009 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1011 /* Setup the PFN for the PDE base of this process */
1013 PointerPte
= MiAddressToPte(PXE_BASE
);
1015 PointerPte
= MiAddressToPte(PDE_BASE
);
1017 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1018 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == PageFrameNumber
* PAGE_SIZE
);
1019 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1021 /* Do the same for hyperspace */
1023 PointerPde
= MiAddressToPxe((PVOID
)HYPER_SPACE
);
1025 PointerPde
= MiAddressToPde(HYPER_SPACE
);
1027 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
1028 //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
1029 MiInitializePfn(PageFrameNumber
, (PMMPTE
)PointerPde
, TRUE
);
1031 /* Setup the PFN for the PTE for the working set */
1032 PointerPte
= MiAddressToPte(MI_WORKING_SET_LIST
);
1033 MI_MAKE_HARDWARE_PTE(&TempPte
, PointerPte
, MM_READWRITE
, 0);
1034 ASSERT(PointerPte
->u
.Long
!= 0);
1035 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1036 MI_WRITE_INVALID_PTE(PointerPte
, DemandZeroPte
);
1037 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1038 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameNumber
;
1039 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1041 /* Now initialize the working set list */
1042 MiInitializeWorkingSetList(Process
);
1045 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1047 /* Release PFN lock */
1048 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1050 /* Lock the VAD, ARM3-owned ranges away */
1051 MiRosTakeOverSharedUserPage(Process
);
1053 /* Check if there's a Section Object */
1056 /* Determine the image file name and save it to EPROCESS */
1057 FileName
= SectionObject
->FileObject
->FileName
;
1058 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
1059 if (FileName
.Buffer
)
1061 /* Loop the file name*/
1062 while (Source
> FileName
.Buffer
)
1064 /* Make sure this isn't a backslash */
1065 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
1067 /* If so, stop it here */
1073 /* Otherwise, keep going */
1079 /* Copy the to the process and truncate it to 15 characters if necessary */
1080 Destination
= Process
->ImageFileName
;
1081 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
1082 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
1083 *Destination
= ANSI_NULL
;
1085 /* Check if caller wants an audit name */
1088 /* Setup the audit name */
1089 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
1092 if (!NT_SUCCESS(Status
))
1100 /* Map the section */
1101 Status
= MmMapViewOfSection(Section
,
1112 /* Save the pointer */
1113 Process
->SectionBaseAddress
= ImageBase
;
1116 /* Be nice and detach */
1119 /* Return status to caller */
1126 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1127 IN PULONG_PTR DirectoryTableBase
)
1129 /* Share the directory base with the idle process */
1130 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1131 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1133 /* Initialize the Addresss Space */
1134 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1135 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1136 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1137 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1138 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1140 /* Use idle process Working set */
1141 Process
->Vm
.VmWorkingSetList
= PsGetCurrentProcess()->Vm
.VmWorkingSetList
;
1144 Process
->HasAddressSpace
= TRUE
;//??
1145 return STATUS_SUCCESS
;
1151 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1153 /* Lock the VAD, ARM3-owned ranges away */
1154 MiRosTakeOverSharedUserPage(Process
);
1155 return STATUS_SUCCESS
;
1159 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1162 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1163 IN PEPROCESS Process
,
1164 OUT PULONG_PTR DirectoryTableBase
)
1167 PFN_NUMBER PdeIndex
, HyperIndex
, WsListIndex
;
1169 MMPTE TempPte
, PdePte
;
1171 PMMPTE SystemTable
, HyperTable
;
1175 /* Choose a process color */
1176 Process
->NextPageColor
= (USHORT
)RtlRandom(&MmProcessColorSeed
);
1178 /* Setup the hyperspace lock */
1179 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1181 /* Lock PFN database */
1182 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1184 /* Get a zero page for the PDE, if possible */
1185 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1186 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1187 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1190 /* No zero pages, grab a free one */
1191 PdeIndex
= MiRemoveAnyPage(Color
);
1193 /* Zero it outside the PFN lock */
1194 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1195 MiZeroPhysicalPage(PdeIndex
);
1196 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1199 /* Get a zero page for hyperspace, if possible */
1200 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1201 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1202 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1205 /* No zero pages, grab a free one */
1206 HyperIndex
= MiRemoveAnyPage(Color
);
1208 /* Zero it outside the PFN lock */
1209 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1210 MiZeroPhysicalPage(HyperIndex
);
1211 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1214 /* Get a zero page for the woring set list, if possible */
1215 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
1216 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1217 WsListIndex
= MiRemoveZeroPageSafe(Color
);
1220 /* No zero pages, grab a free one */
1221 WsListIndex
= MiRemoveAnyPage(Color
);
1223 /* Zero it outside the PFN lock */
1224 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1225 MiZeroPhysicalPage(WsListIndex
);
1229 /* Release the PFN lock */
1230 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1233 /* Switch to phase 1 initialization */
1234 ASSERT(Process
->AddressSpaceInitialized
== 0);
1235 Process
->AddressSpaceInitialized
= 1;
1237 /* Set the base directory pointers */
1238 Process
->WorkingSetPage
= WsListIndex
;
1239 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1240 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1242 /* Make sure we don't already have a page directory setup */
1243 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1245 /* Get a PTE to map hyperspace */
1246 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1247 ASSERT(PointerPte
!= NULL
);
1250 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1255 /* Set it dirty and map it */
1256 MI_MAKE_DIRTY_PAGE(&PdePte
);
1257 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1259 /* Now get hyperspace's page table */
1260 HyperTable
= MiPteToAddress(PointerPte
);
1262 /* Now write the PTE/PDE entry for the working set list index itself */
1263 TempPte
= ValidKernelPte
;
1264 TempPte
.u
.Hard
.PageFrameNumber
= WsListIndex
;
1265 /* Hyperspace is local */
1266 MI_MAKE_LOCAL_PAGE(&TempPte
);
1267 PdeOffset
= MiAddressToPteOffset(MmWorkingSetList
);
1268 HyperTable
[PdeOffset
] = TempPte
;
1270 /* Let go of the system PTE */
1271 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1273 /* Save the PTE address of the page directory itself */
1274 Pfn1
= MiGetPfnEntry(PdeIndex
);
1275 Pfn1
->PteAddress
= (PMMPTE
)PDE_BASE
;
1277 /* Insert us into the Mm process list */
1278 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1280 /* Get a PTE to map the page directory */
1281 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1282 ASSERT(PointerPte
!= NULL
);
1285 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1290 /* Set it dirty and map it */
1291 MI_MAKE_DIRTY_PAGE(&PdePte
);
1292 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1294 /* Now get the page directory (which we'll double map, so call it a page table */
1295 SystemTable
= MiPteToAddress(PointerPte
);
1297 /* Copy all the kernel mappings */
1298 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1299 RtlCopyMemory(&SystemTable
[PdeOffset
],
1300 MiAddressToPde(MmSystemRangeStart
),
1301 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1303 /* Now write the PTE/PDE entry for hyperspace itself */
1304 TempPte
= ValidKernelPte
;
1305 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1306 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1307 SystemTable
[PdeOffset
] = TempPte
;
1311 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1313 /* Now do the x86 trick of making the PDE a page table itself */
1314 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1315 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1316 SystemTable
[PdeOffset
] = TempPte
;
1318 /* Let go of the system PTE */
1319 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1326 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1329 PMM_AVL_TABLE VadTree
;
1330 PETHREAD Thread
= PsGetCurrentThread();
1332 /* Only support this */
1333 ASSERT(Process
->AddressSpaceInitialized
== 2);
1335 /* Lock the process address space from changes */
1336 MmLockAddressSpace(&Process
->Vm
);
1338 /* VM is deleted now */
1339 Process
->VmDeleted
= TRUE
;
1341 /* Enumerate the VADs */
1342 VadTree
= &Process
->VadRoot
;
1343 while (VadTree
->NumberGenericTableElements
)
1345 /* Grab the current VAD */
1346 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1348 /* Lock the working set */
1349 MiLockProcessWorkingSet(Process
, Thread
);
1351 /* Remove this VAD from the tree */
1352 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1353 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1355 /* Only regular VADs supported for now */
1356 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1358 /* Check if this is a section VAD */
1359 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1361 /* Remove the view */
1362 MiRemoveMappedView(Process
, Vad
);
1366 /* Delete the addresses */
1367 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1368 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1371 /* Release the working set */
1372 MiUnlockProcessWorkingSet(Process
, Thread
);
1375 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1376 if (Vad
->u
.VadFlags
.Spare
== 1)
1378 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1379 Vad
->u
.VadFlags
.Spare
= 2;
1383 /* Free the VAD memory */
1386 /* Delete the shared user data section */
1387 MiDeleteVirtualAddresses(USER_SHARED_DATA
, USER_SHARED_DATA
, NULL
);
1389 /* Release the address space */
1390 MmUnlockAddressSpace(&Process
->Vm
);
1395 MmDeleteProcessAddressSpace2(IN PEPROCESS Process
)
1399 PFN_NUMBER PageFrameIndex
;
1401 //ASSERT(Process->CommitCharge == 0);
1403 /* Acquire the PFN lock */
1404 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1406 /* Check for fully initialized process */
1407 if (Process
->AddressSpaceInitialized
== 2)
1409 /* Map the working set page and its page table */
1410 Pfn1
= MiGetPfnEntry(Process
->WorkingSetPage
);
1411 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1414 MI_SET_PFN_DELETED(Pfn1
);
1415 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1416 MiDecrementShareCount(Pfn1
, Process
->WorkingSetPage
);
1417 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1418 MiReleaseSystemPtes(MiAddressToPte(Process
->Vm
.VmWorkingSetList
), 1, SystemPteSpace
);
1420 /* Now map hyperspace and its page table */
1421 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
;
1422 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1423 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1426 MI_SET_PFN_DELETED(Pfn1
);
1427 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1428 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1429 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1431 /* Finally, nuke the PDE itself */
1432 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
;
1433 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1434 MI_SET_PFN_DELETED(Pfn1
);
1435 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1436 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1438 /* Page table is now dead. Bye bye... */
1439 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1443 /* A partly-initialized process should never exit through here */
1447 /* Release the PFN lock */
1448 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1450 /* No support for sessions yet */
1451 ASSERT(Process
->Session
== 0);
1453 /* Clear out the PDE pages */
1454 Process
->Pcb
.DirectoryTableBase
[0] = 0;
1455 Process
->Pcb
.DirectoryTableBase
[1] = 0;
1458 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
1460 PMM_SESSION_SPACE MmSessionSpace
;
1461 PFN_NUMBER MiSessionDataPages
, MiSessionTagPages
, MiSessionTagSizePages
;
1462 PFN_NUMBER MiSessionBigPoolPages
, MiSessionCreateCharge
;
1463 KGUARDED_MUTEX MiSessionIdMutex
;
1464 LONG MmSessionDataPages
;
1465 PRTL_BITMAP MiSessionIdBitmap
;
1466 volatile LONG MiSessionLeaderExists
;
1470 MiInitializeSessionIds(VOID
)
1472 ULONG Size
, BitmapSize
;
1473 PFN_NUMBER TotalPages
;
1475 /* Setup the total number of data pages needed for the structure */
1476 TotalPages
= MI_SESSION_DATA_PAGES_MAXIMUM
;
1477 MiSessionDataPages
= ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE
)) >> PAGE_SHIFT
;
1478 ASSERT(MiSessionDataPages
<= MI_SESSION_DATA_PAGES_MAXIMUM
- 3);
1479 TotalPages
-= MiSessionDataPages
;
1481 /* Setup the number of pages needed for session pool tags */
1482 MiSessionTagSizePages
= 2;
1483 MiSessionBigPoolPages
= 1;
1484 MiSessionTagPages
= MiSessionTagSizePages
+ MiSessionBigPoolPages
;
1485 ASSERT(MiSessionTagPages
<= TotalPages
);
1486 ASSERT(MiSessionTagPages
< MI_SESSION_TAG_PAGES_MAXIMUM
);
1488 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
1489 MiSessionCreateCharge
= 1 + MiSessionDataPages
+ MiSessionTagPages
;
1491 /* Initialize the lock */
1492 KeInitializeGuardedMutex(&MiSessionIdMutex
);
1494 /* Allocate the bitmap */
1495 Size
= MI_INITIAL_SESSION_IDS
;
1496 BitmapSize
= ((Size
+ 31) / 32) * sizeof(ULONG
);
1497 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
1498 sizeof(RTL_BITMAP
) + BitmapSize
,
1500 if (MiSessionIdBitmap
)
1502 /* Free all the bits */
1503 RtlInitializeBitMap(MiSessionIdBitmap
,
1504 (PVOID
)(MiSessionIdBitmap
+ 1),
1506 RtlClearAllBits(MiSessionIdBitmap
);
1510 /* Die if we couldn't allocate the bitmap */
1511 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1512 MmNumberOfPhysicalPages
,
1513 MmLowestPhysicalPage
,
1514 MmHighestPhysicalPage
,
1521 MiSessionLeader(IN PEPROCESS Process
)
1525 /* Set the flag while under the expansion lock */
1526 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
1527 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
1528 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
1533 MiSessionCreateInternal(OUT PULONG SessionId
)
1535 PEPROCESS Process
= PsGetCurrentProcess();
1536 ULONG NewFlags
, Flags
, Size
, i
, Color
;
1538 PMMPTE PointerPte
, PageTables
, SessionPte
;
1540 PMM_SESSION_SPACE SessionGlobal
;
1544 PFN_NUMBER SessionPageDirIndex
;
1545 PFN_NUMBER TagPage
[MI_SESSION_TAG_PAGES_MAXIMUM
];
1546 PFN_NUMBER DataPage
[MI_SESSION_DATA_PAGES_MAXIMUM
];
1548 /* This should not exist yet */
1549 ASSERT(MmIsAddressValid(MmSessionSpace
) == FALSE
);
1551 /* Loop so we can set the session-is-creating flag */
1552 Flags
= Process
->Flags
;
1555 /* Check if it's already set */
1556 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
1559 DPRINT1("Lost session race\n");
1560 return STATUS_ALREADY_COMMITTED
;
1563 /* Now try to set it */
1564 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
1565 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
1567 if (NewFlags
== Flags
) break;
1569 /* It changed, try again */
1573 /* Now we should own the flag */
1574 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1577 * Session space covers everything from 0xA0000000 to 0xC0000000.
1578 * Allocate enough page tables to describe the entire region
1580 Size
= (0x20000000 / PDE_MAPPED_VA
) * sizeof(MMPTE
);
1581 PageTables
= ExAllocatePoolWithTag(NonPagedPool
, Size
, 'tHmM');
1582 ASSERT(PageTables
!= NULL
);
1583 RtlZeroMemory(PageTables
, Size
);
1585 /* Lock the session ID creation mutex */
1586 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1588 /* Allocate a new Session ID */
1589 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
1590 if (*SessionId
== 0xFFFFFFFF)
1592 /* We ran out of session IDs, we should expand */
1593 DPRINT1("Too many sessions created. Expansion not yet supported\n");
1594 return STATUS_NO_MEMORY
;
1597 /* Unlock the session ID creation mutex */
1598 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1600 /* Reserve the global PTEs */
1601 SessionPte
= MiReserveSystemPtes(MiSessionDataPages
, SystemPteSpace
);
1602 ASSERT(SessionPte
!= NULL
);
1604 /* Acquire the PFN lock while we set everything up */
1605 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1607 /* Loop the global PTEs */
1608 TempPte
.u
.Long
= ValidKernelPte
.u
.Long
;
1609 for (i
= 0; i
< MiSessionDataPages
; i
++)
1611 /* Get a zeroed colored zero page */
1612 Color
= MI_GET_NEXT_COLOR();
1613 DataPage
[i
] = MiRemoveZeroPageSafe(Color
);
1616 /* No zero pages, grab a free one */
1617 DataPage
[i
] = MiRemoveAnyPage(Color
);
1619 /* Zero it outside the PFN lock */
1620 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1621 MiZeroPhysicalPage(DataPage
[i
]);
1622 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1625 /* Fill the PTE out */
1626 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1627 MI_WRITE_VALID_PTE(SessionPte
+ i
, TempPte
);
1630 /* Set the pointer to global space */
1631 SessionGlobal
= MiPteToAddress(SessionPte
);
1633 /* Get a zeroed colored zero page */
1634 Color
= MI_GET_NEXT_COLOR();
1635 SessionPageDirIndex
= MiRemoveZeroPageSafe(Color
);
1636 if (!SessionPageDirIndex
)
1638 /* No zero pages, grab a free one */
1639 SessionPageDirIndex
= MiRemoveAnyPage(Color
);
1641 /* Zero it outside the PFN lock */
1642 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1643 MiZeroPhysicalPage(SessionPageDirIndex
);
1644 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1647 /* Fill the PTE out */
1648 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
1649 TempPte
.u
.Hard
.PageFrameNumber
= SessionPageDirIndex
;
1651 /* Setup, allocate, fill out the MmSessionSpace PTE */
1652 PointerPde
= MiAddressToPde(MmSessionSpace
);
1653 ASSERT(PointerPde
->u
.Long
== 0);
1654 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1655 MiInitializePfnForOtherProcess(SessionPageDirIndex
,
1657 SessionPageDirIndex
);
1658 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex
)->u1
.WsIndex
== 0);
1660 /* Loop all the local PTEs for it */
1661 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
1662 PointerPte
= MiAddressToPte(MmSessionSpace
);
1663 for (i
= 0; i
< MiSessionDataPages
; i
++)
1665 /* And fill them out */
1666 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1667 MiInitializePfnAndMakePteValid(DataPage
[i
], PointerPte
+ i
, TempPte
);
1668 ASSERT(MI_PFN_ELEMENT(DataPage
[i
])->u1
.WsIndex
== 0);
1671 /* Finally loop all of the session pool tag pages */
1672 for (i
= 0; i
< MiSessionTagPages
; i
++)
1674 /* Grab a zeroed colored page */
1675 Color
= MI_GET_NEXT_COLOR();
1676 TagPage
[i
] = MiRemoveZeroPageSafe(Color
);
1679 /* No zero pages, grab a free one */
1680 TagPage
[i
] = MiRemoveAnyPage(Color
);
1682 /* Zero it outside the PFN lock */
1683 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1684 MiZeroPhysicalPage(TagPage
[i
]);
1685 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1688 /* Fill the PTE out */
1689 TempPte
.u
.Hard
.PageFrameNumber
= TagPage
[i
];
1690 MiInitializePfnAndMakePteValid(TagPage
[i
],
1691 PointerPte
+ MiSessionDataPages
+ i
,
1695 /* PTEs have been setup, release the PFN lock */
1696 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1698 /* Fill out the session space structure now */
1699 MmSessionSpace
->GlobalVirtualAddress
= SessionGlobal
;
1700 MmSessionSpace
->ReferenceCount
= 1;
1701 MmSessionSpace
->ResidentProcessCount
= 1;
1702 MmSessionSpace
->u
.LongFlags
= 0;
1703 MmSessionSpace
->SessionId
= *SessionId
;
1704 MmSessionSpace
->LocaleId
= PsDefaultSystemLocaleId
;
1705 MmSessionSpace
->SessionPageDirectoryIndex
= SessionPageDirIndex
;
1706 MmSessionSpace
->Color
= Color
;
1707 MmSessionSpace
->NonPageablePages
= MiSessionCreateCharge
;
1708 MmSessionSpace
->CommittedPages
= MiSessionCreateCharge
;
1709 MmSessionSpace
->PageTables
= PageTables
;
1710 MmSessionSpace
->PageTables
[PointerPde
- MiAddressToPde(MmSessionBase
)] = *PointerPde
;
1711 InitializeListHead(&MmSessionSpace
->ImageList
);
1712 DPRINT1("Session %d is ready to go: 0x%p 0x%p, %lx 0x%p\n",
1713 *SessionId
, MmSessionSpace
, SessionGlobal
, SessionPageDirIndex
, PageTables
);
1715 /* Initialize session pool */
1716 //Status = MiInitializeSessionPool();
1717 Status
= STATUS_SUCCESS
;
1718 ASSERT(NT_SUCCESS(Status
) == TRUE
);
1720 /* Initialize system space */
1721 Result
= MiInitializeSystemSpaceMap(&SessionGlobal
->Session
);
1722 ASSERT(Result
== TRUE
);
1724 /* Initialize the process list, make sure the workign set list is empty */
1725 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
1726 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
1727 InitializeListHead(&SessionGlobal
->ProcessList
);
1729 /* We're done, clear the flag */
1730 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1731 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
1733 /* Insert the process into the session */
1734 ASSERT(Process
->Session
== NULL
);
1735 ASSERT(SessionGlobal
->ProcessReferenceToSession
== 0);
1736 SessionGlobal
->ProcessReferenceToSession
= 1;
1739 InterlockedIncrement(&MmSessionDataPages
);
1740 return STATUS_SUCCESS
;
1745 MmSessionCreate(OUT PULONG SessionId
)
1747 PEPROCESS Process
= PsGetCurrentProcess();
1748 ULONG SessionLeaderExists
;
1751 /* Fail if the process is already in a session */
1752 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
1754 DPRINT1("Process already in session\n");
1755 return STATUS_ALREADY_COMMITTED
;
1758 /* Check if the process is already the session leader */
1759 if (!Process
->Vm
.Flags
.SessionLeader
)
1761 /* Atomically set it as the leader */
1762 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
1763 if (SessionLeaderExists
)
1765 DPRINT1("Session leader race\n");
1766 return STATUS_INVALID_SYSTEM_SERVICE
;
1769 /* Do the work required to upgrade him */
1770 MiSessionLeader(Process
);
1773 /* FIXME: Actually create a session */
1774 KeEnterCriticalRegion();
1775 Status
= MiSessionCreateInternal(SessionId
);
1776 KeLeaveCriticalRegion();
1778 /* Set and assert the flags, and return */
1779 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
1780 ASSERT(MiSessionLeaderExists
== 1);
1786 MmSessionDelete(IN ULONG SessionId
)
1788 PEPROCESS Process
= PsGetCurrentProcess();
1790 /* Process must be in a session */
1791 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
1793 DPRINT1("Not in a session!\n");
1794 return STATUS_UNABLE_TO_FREE_VM
;
1797 /* It must be the session leader */
1798 if (!Process
->Vm
.Flags
.SessionLeader
)
1800 DPRINT1("Not a session leader!\n");
1801 return STATUS_UNABLE_TO_FREE_VM
;
1804 /* Remove one reference count */
1805 KeEnterCriticalRegion();
1807 KeLeaveCriticalRegion();
1810 return STATUS_SUCCESS
;
1813 /* SYSTEM CALLS ***************************************************************/
1817 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1818 IN OUT PULONG_PTR NumberOfPages
,
1819 IN OUT PULONG_PTR UserPfnArray
)
1822 return STATUS_NOT_IMPLEMENTED
;
1827 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1828 IN ULONG_PTR NumberOfPages
,
1829 IN OUT PULONG_PTR UserPfnArray
)
1832 return STATUS_NOT_IMPLEMENTED
;
1837 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1838 IN ULONG_PTR NumberOfPages
,
1839 IN OUT PULONG_PTR UserPfnArray
)
1842 return STATUS_NOT_IMPLEMENTED
;
1847 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1848 IN OUT PULONG_PTR NumberOfPages
,
1849 IN OUT PULONG_PTR UserPfnArray
)
1852 return STATUS_NOT_IMPLEMENTED
;