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
)
123 ExFreePoolWithTag(Vad
, 'ldaV');
124 return STATUS_NO_MEMORY
;
128 /* Validate that it came from the VAD ranges */
129 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
131 /* Build the rest of the VAD now */
132 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
133 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
134 Vad
->u3
.Secured
.StartVpn
= *Base
;
135 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
136 Vad
->u1
.Parent
= NULL
;
138 /* FIXME: Should setup VAD bitmap */
139 Status
= STATUS_SUCCESS
;
141 /* Pretend as if we own the working set */
142 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
145 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
146 Process
->VadRoot
.NodeHint
= Vad
;
147 Vad
->ControlArea
= NULL
; // For Memory-Area hack
148 Vad
->FirstPrototypePte
= NULL
;
149 DPRINT("VAD: %p\n", Vad
);
150 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
151 MiInsertNode(&Process
->VadRoot
, (PVOID
)Vad
, Parent
, Result
);
153 /* Release the working set */
154 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
156 /* Release the address space lock */
157 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
159 /* Return the status */
165 MmDeleteTeb(IN PEPROCESS Process
,
169 PETHREAD Thread
= PsGetCurrentThread();
171 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
172 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
174 /* TEB is one page */
175 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
177 /* Attach to the process */
178 KeAttachProcess(&Process
->Pcb
);
180 /* Lock the process address space */
181 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
183 /* Find the VAD, make sure it's a TEB VAD */
184 Vad
= MiLocateAddress(Teb
);
185 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
187 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
189 /* Bug in the AVL code? */
190 DPRINT1("Corrupted VAD!\n");
194 /* Sanity checks for a valid TEB VAD */
195 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
196 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
197 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
198 ASSERT(Vad
->u2
.VadFlags2
.OneSecured
== TRUE
);
199 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
201 /* Lock the working set */
202 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
204 /* Remove this VAD from the tree */
205 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
206 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
208 /* Delete the pages */
209 MiDeleteVirtualAddresses((ULONG_PTR
)Teb
, TebEnd
, NULL
);
211 /* Release the working set */
212 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
218 /* Release the address space lock */
219 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
227 MmDeleteKernelStack(IN PVOID StackBase
,
231 PFN_NUMBER PageFrameNumber
, PageTableFrameNumber
;
232 PFN_COUNT StackPages
;
238 // This should be the guard page, so decrement by one
240 PointerPte
= MiAddressToPte(StackBase
);
244 // If this is a small stack, just push the stack onto the dead stack S-LIST
248 if (ExQueryDepthSList(&MmDeadStackSListHead
) < MmMaximumDeadKernelStacks
)
250 Pfn1
= MiGetPfnEntry(PointerPte
->u
.Hard
.PageFrameNumber
);
251 InterlockedPushEntrySList(&MmDeadStackSListHead
,
252 (PSLIST_ENTRY
)&Pfn1
->u1
.NextStackPfn
);
258 // Calculate pages used
260 StackPages
= BYTES_TO_PAGES(GuiStack
?
261 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
263 /* Acquire the PFN lock */
264 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
269 for (i
= 0; i
< StackPages
; i
++)
272 // Check if this is a valid PTE
274 if (PointerPte
->u
.Hard
.Valid
== 1)
276 /* Get the PTE's page */
277 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
278 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
280 /* Now get the page of the page table mapping it */
281 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
282 Pfn2
= MiGetPfnEntry(PageTableFrameNumber
);
284 /* Remove a shared reference, since the page is going away */
285 MiDecrementShareCount(Pfn2
, PageTableFrameNumber
);
287 /* Set the special pending delete marker */
288 MI_SET_PFN_DELETED(Pfn1
);
290 /* And now delete the actual stack page */
291 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
301 // We should be at the guard page now
303 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
305 /* Release the PFN lock */
306 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
311 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
316 MmCreateKernelStack(IN BOOLEAN GuiStack
,
319 PFN_COUNT StackPtes
, StackPages
;
320 PMMPTE PointerPte
, StackPte
;
322 MMPTE TempPte
, InvalidPte
;
324 PFN_NUMBER PageFrameIndex
;
329 // Calculate pages needed
334 // We'll allocate 64KB stack, but only commit 12K
336 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
337 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
343 // If the dead stack S-LIST has a stack on it, use it instead of allocating
344 // new system PTEs for this stack
346 if (ExQueryDepthSList(&MmDeadStackSListHead
))
348 Pfn1
= (PMMPFN
)InterlockedPopEntrySList(&MmDeadStackSListHead
);
351 PointerPte
= Pfn1
->PteAddress
;
352 BaseAddress
= MiPteToAddress(++PointerPte
);
358 // We'll allocate 12K and that's it
360 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
361 StackPages
= StackPtes
;
365 // Reserve stack pages, plus a guard page
367 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
368 if (!StackPte
) return NULL
;
371 // Get the stack address
373 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
376 // Select the right PTE address where we actually start committing pages
378 PointerPte
= StackPte
;
379 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
380 KERNEL_LARGE_STACK_COMMIT
);
383 /* Setup the temporary invalid PTE */
384 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
386 /* Setup the template stack PTE */
387 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
390 // Acquire the PFN DB lock
392 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
395 // Loop each stack page
397 for (i
= 0; i
< StackPages
; i
++)
404 /* Get a page and write the current invalid PTE */
405 MI_SET_USAGE(MI_USAGE_KERNEL_STACK
);
406 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
407 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
408 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
410 /* Initialize the PFN entry for this page */
411 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
413 /* Write the valid PTE */
414 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
415 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
419 // Release the PFN lock
421 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
424 // Return the stack address
431 MmGrowKernelStackEx(IN PVOID StackPointer
,
434 PKTHREAD Thread
= KeGetCurrentThread();
435 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
437 MMPTE TempPte
, InvalidPte
;
438 PFN_NUMBER PageFrameIndex
;
441 // Make sure the stack did not overflow
443 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
444 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
447 // Get the current stack limit
449 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
450 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
453 // Get the new one and make sure this isn't a retarded request
455 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
456 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
459 // Now make sure you're not going past the reserved space
461 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
462 KERNEL_LARGE_STACK_SIZE
));
463 if (NewLimitPte
< LastPte
)
468 DPRINT1("Thread wants too much stack\n");
469 return STATUS_STACK_OVERFLOW
;
473 // Calculate the number of new pages
477 /* Setup the temporary invalid PTE */
478 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
481 // Acquire the PFN DB lock
483 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
486 // Loop each stack page
488 while (LimitPte
>= NewLimitPte
)
490 /* Get a page and write the current invalid PTE */
491 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION
);
492 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
493 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
494 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
496 /* Initialize the PFN entry for this page */
497 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
499 /* Setup the template stack PTE */
500 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
502 /* Write the valid PTE */
503 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
507 // Release the PFN lock
509 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
514 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
515 return STATUS_SUCCESS
;
520 MmGrowKernelStack(IN PVOID StackPointer
)
523 // Call the extended version
525 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
530 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
531 IN UCHAR MemoryPriority
)
536 // Check if we have less then 16MB of Physical Memory
538 if ((MmSystemSize
== MmSmallSystem
) &&
539 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
542 // Always use background priority
544 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
548 // Save the old priority and update it
550 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
551 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
554 // Return the old priority
561 MmGetSessionLocaleId(VOID
)
567 // Get the current process
569 Process
= PsGetCurrentProcess();
572 // Check if it's the Session Leader
574 if (Process
->Vm
.Flags
.SessionLeader
)
577 // Make sure it has a valid Session
579 if (Process
->Session
)
584 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
589 // Not a session leader, return the default
591 return PsDefaultThreadLocaleId
;
596 MmCreatePeb(IN PEPROCESS Process
,
597 IN PINITIAL_PEB InitialPeb
,
601 LARGE_INTEGER SectionOffset
;
603 PVOID TableBase
= NULL
;
604 PIMAGE_NT_HEADERS NtHeaders
;
605 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
607 USHORT Characteristics
;
608 KAFFINITY ProcessAffinityMask
= 0;
609 SectionOffset
.QuadPart
= (ULONGLONG
)0;
615 KeAttachProcess(&Process
->Pcb
);
620 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
630 DPRINT("NLS Tables at: %p\n", TableBase
);
631 if (!NT_SUCCESS(Status
))
633 /* Cleanup and exit */
641 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
642 DPRINT("PEB at: %p\n", Peb
);
643 if (!NT_SUCCESS(Status
))
645 /* Cleanup and exit */
651 // Use SEH in case we can't load the PEB
656 // Initialize the PEB
658 RtlZeroMemory(Peb
, sizeof(PEB
));
663 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
664 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
665 Peb
->Mutant
= InitialPeb
->Mutant
;
666 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
671 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
672 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
673 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
676 // Default Version Data (could get changed below)
678 Peb
->OSMajorVersion
= NtMajorVersion
;
679 Peb
->OSMinorVersion
= NtMinorVersion
;
680 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
681 Peb
->OSPlatformId
= VER_PLATFORM_WIN32_NT
;
682 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
685 // Heap and Debug Data
687 Peb
->NumberOfProcessors
= KeNumberProcessors
;
688 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
);
689 Peb
->NtGlobalFlag
= NtGlobalFlag
;
690 Peb
->HeapSegmentReserve
= MmHeapSegmentReserve
;
691 Peb
->HeapSegmentCommit
= MmHeapSegmentCommit
;
692 Peb
->HeapDeCommitTotalFreeThreshold
= MmHeapDeCommitTotalFreeThreshold
;
693 Peb
->HeapDeCommitFreeBlockThreshold
= MmHeapDeCommitFreeBlockThreshold
;
694 Peb
->CriticalSectionTimeout
= MmCriticalSectionTimeout
;
695 Peb
->MinimumStackCommit
= MmMinimumStackCommitInBytes
;
696 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
697 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
702 MmGetSessionId(Process
);
704 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
710 _SEH2_YIELD(return _SEH2_GetExceptionCode());
715 // Use SEH in case we can't load the image
722 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
723 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
725 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
731 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
741 // Use SEH in case we can't load the headers
746 // Get the Image Config Data too
748 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
750 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
757 ProbeForRead(ImageConfigData
,
758 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
763 // Write subsystem data
765 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
766 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
767 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
770 // Check for version data
772 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
775 // Extract values and write them
777 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
778 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
779 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
780 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
782 /* Process CSD version override */
783 if ((ImageConfigData
) && (ImageConfigData
->CSDVersion
))
785 /* Take the value from the image configuration directory */
786 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
790 /* Process optional process affinity mask override */
791 if ((ImageConfigData
) && (ImageConfigData
->ProcessAffinityMask
))
793 /* Take the value from the image configuration directory */
794 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
798 // Check if this is a UP image
799 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
802 // Force it to use CPU 0
804 /* FIXME: this should use the MmRotatingUniprocessorNumber */
805 Peb
->ImageProcessAffinityMask
= 0;
810 // Whatever was configured
812 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
821 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
827 // Detach from the Process
831 return STATUS_SUCCESS
;
836 MmCreateTeb(IN PEPROCESS Process
,
837 IN PCLIENT_ID ClientId
,
838 IN PINITIAL_TEB InitialTeb
,
842 NTSTATUS Status
= STATUS_SUCCESS
;
848 KeAttachProcess(&Process
->Pcb
);
853 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
854 ASSERT(NT_SUCCESS(Status
));
857 // Use SEH in case we can't load the TEB
862 // Initialize the PEB
864 RtlZeroMemory(Teb
, sizeof(TEB
));
870 Teb
->NtTib
.ExceptionList
= NULL
;
872 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
874 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
877 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
879 Teb
->NtTib
.Version
= 30 << 8;
884 Teb
->ClientId
= *ClientId
;
885 Teb
->RealClientId
= *ClientId
;
886 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
887 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
890 // Check if we have a grandparent TEB
892 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
893 (InitialTeb
->PreviousStackLimit
== NULL
))
896 // Use initial TEB values
898 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
899 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
900 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
905 // Use grandparent TEB values
907 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
908 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
912 // Initialize the static unicode string
914 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
915 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
922 Status
= _SEH2_GetExceptionCode();
936 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess
)
942 /* Setup some bogus list data */
943 MmWorkingSetList
->LastEntry
= CurrentProcess
->Vm
.MinimumWorkingSetSize
;
944 MmWorkingSetList
->HashTable
= NULL
;
945 MmWorkingSetList
->HashTableSize
= 0;
946 MmWorkingSetList
->NumberOfImageWaiters
= 0;
947 MmWorkingSetList
->Wsle
= (PVOID
)0xDEADBABE;
948 MmWorkingSetList
->VadBitMapHint
= 1;
949 MmWorkingSetList
->HashTableStart
= (PVOID
)0xBADAB00B;
950 MmWorkingSetList
->HighestPermittedHashAddress
= (PVOID
)0xCAFEBABE;
951 MmWorkingSetList
->FirstFree
= 1;
952 MmWorkingSetList
->FirstDynamic
= 2;
953 MmWorkingSetList
->NextSlot
= 3;
954 MmWorkingSetList
->LastInitializedWsle
= 4;
956 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
957 Pfn1
= MiGetPfnEntry(CurrentProcess
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
);
958 ASSERT(Pfn1
->u4
.PteFrame
== MiGetPfnEntryIndex(Pfn1
));
959 Pfn1
->u1
.Event
= (PKEVENT
)CurrentProcess
;
961 /* Map the process working set in kernel space */
962 sysPte
= MiReserveSystemPtes(1, SystemPteSpace
);
963 MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte
, sysPte
, MM_READWRITE
, CurrentProcess
->WorkingSetPage
);
964 MI_WRITE_VALID_PTE(sysPte
, tempPte
);
965 CurrentProcess
->Vm
.VmWorkingSetList
= MiPteToAddress(sysPte
);
970 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
971 IN PEPROCESS ProcessClone OPTIONAL
,
972 IN PVOID Section OPTIONAL
,
974 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
976 NTSTATUS Status
= STATUS_SUCCESS
;
979 PROS_SECTION_OBJECT SectionObject
= Section
;
983 PFN_NUMBER PageFrameNumber
;
984 UNICODE_STRING FileName
;
990 /* We should have a PDE */
991 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
992 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
994 /* Attach to the process */
995 KeAttachProcess(&Process
->Pcb
);
997 /* The address space should now been in phase 1 or 0 */
998 ASSERT(Process
->AddressSpaceInitialized
<= 1);
999 Process
->AddressSpaceInitialized
= 2;
1001 /* Initialize the Addresss Space lock */
1002 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1003 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1005 /* Initialize AVL tree */
1006 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1007 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1009 /* Lock PFN database */
1010 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1012 /* Setup the PFN for the PDE base of this process */
1014 PointerPte
= MiAddressToPte(PXE_BASE
);
1016 PointerPte
= MiAddressToPte(PDE_BASE
);
1018 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1019 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == PageFrameNumber
* PAGE_SIZE
);
1020 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1022 /* Do the same for hyperspace */
1024 PointerPde
= MiAddressToPxe((PVOID
)HYPER_SPACE
);
1026 PointerPde
= MiAddressToPde(HYPER_SPACE
);
1028 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
1029 //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
1030 MiInitializePfn(PageFrameNumber
, (PMMPTE
)PointerPde
, TRUE
);
1032 /* Setup the PFN for the PTE for the working set */
1033 PointerPte
= MiAddressToPte(MI_WORKING_SET_LIST
);
1034 MI_MAKE_HARDWARE_PTE(&TempPte
, PointerPte
, MM_READWRITE
, 0);
1035 ASSERT(PointerPte
->u
.Long
!= 0);
1036 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1037 MI_WRITE_INVALID_PTE(PointerPte
, DemandZeroPte
);
1038 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1039 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameNumber
;
1040 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1042 /* Now initialize the working set list */
1043 MiInitializeWorkingSetList(Process
);
1046 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1048 /* Release PFN lock */
1049 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1051 /* Lock the VAD, ARM3-owned ranges away */
1052 MiRosTakeOverSharedUserPage(Process
);
1054 /* Check if there's a Section Object */
1057 /* Determine the image file name and save it to EPROCESS */
1058 FileName
= SectionObject
->FileObject
->FileName
;
1059 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
1060 if (FileName
.Buffer
)
1062 /* Loop the file name*/
1063 while (Source
> FileName
.Buffer
)
1065 /* Make sure this isn't a backslash */
1066 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
1068 /* If so, stop it here */
1074 /* Otherwise, keep going */
1080 /* Copy the to the process and truncate it to 15 characters if necessary */
1081 Destination
= Process
->ImageFileName
;
1082 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
1083 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
1084 *Destination
= ANSI_NULL
;
1086 /* Check if caller wants an audit name */
1089 /* Setup the audit name */
1090 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
1093 if (!NT_SUCCESS(Status
))
1101 /* Map the section */
1102 Status
= MmMapViewOfSection(Section
,
1113 /* Save the pointer */
1114 Process
->SectionBaseAddress
= ImageBase
;
1117 /* Be nice and detach */
1120 /* Return status to caller */
1127 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1128 IN PULONG_PTR DirectoryTableBase
)
1130 /* Share the directory base with the idle process */
1131 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1132 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1134 /* Initialize the Addresss Space */
1135 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1136 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1137 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1138 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1139 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1141 /* Use idle process Working set */
1142 Process
->Vm
.VmWorkingSetList
= PsGetCurrentProcess()->Vm
.VmWorkingSetList
;
1145 Process
->HasAddressSpace
= TRUE
;//??
1146 return STATUS_SUCCESS
;
1152 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1154 /* Lock the VAD, ARM3-owned ranges away */
1155 MiRosTakeOverSharedUserPage(Process
);
1156 return STATUS_SUCCESS
;
1160 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1163 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1164 IN PEPROCESS Process
,
1165 OUT PULONG_PTR DirectoryTableBase
)
1168 PFN_NUMBER PdeIndex
, HyperIndex
, WsListIndex
;
1170 MMPTE TempPte
, PdePte
;
1172 PMMPTE SystemTable
, HyperTable
;
1176 /* Choose a process color */
1177 Process
->NextPageColor
= (USHORT
)RtlRandom(&MmProcessColorSeed
);
1179 /* Setup the hyperspace lock */
1180 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1182 /* Lock PFN database */
1183 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1185 /* Get a zero page for the PDE, if possible */
1186 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1187 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1188 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1191 /* No zero pages, grab a free one */
1192 PdeIndex
= MiRemoveAnyPage(Color
);
1194 /* Zero it outside the PFN lock */
1195 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1196 MiZeroPhysicalPage(PdeIndex
);
1197 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1200 /* Get a zero page for hyperspace, if possible */
1201 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1202 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1203 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1206 /* No zero pages, grab a free one */
1207 HyperIndex
= MiRemoveAnyPage(Color
);
1209 /* Zero it outside the PFN lock */
1210 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1211 MiZeroPhysicalPage(HyperIndex
);
1212 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1215 /* Get a zero page for the woring set list, if possible */
1216 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
1217 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1218 WsListIndex
= MiRemoveZeroPageSafe(Color
);
1221 /* No zero pages, grab a free one */
1222 WsListIndex
= MiRemoveAnyPage(Color
);
1224 /* Zero it outside the PFN lock */
1225 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1226 MiZeroPhysicalPage(WsListIndex
);
1230 /* Release the PFN lock */
1231 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1234 /* Switch to phase 1 initialization */
1235 ASSERT(Process
->AddressSpaceInitialized
== 0);
1236 Process
->AddressSpaceInitialized
= 1;
1238 /* Set the base directory pointers */
1239 Process
->WorkingSetPage
= WsListIndex
;
1240 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1241 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1243 /* Make sure we don't already have a page directory setup */
1244 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1246 /* Get a PTE to map hyperspace */
1247 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1248 ASSERT(PointerPte
!= NULL
);
1251 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1256 /* Set it dirty and map it */
1257 MI_MAKE_DIRTY_PAGE(&PdePte
);
1258 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1260 /* Now get hyperspace's page table */
1261 HyperTable
= MiPteToAddress(PointerPte
);
1263 /* Now write the PTE/PDE entry for the working set list index itself */
1264 TempPte
= ValidKernelPte
;
1265 TempPte
.u
.Hard
.PageFrameNumber
= WsListIndex
;
1266 /* Hyperspace is local */
1267 MI_MAKE_LOCAL_PAGE(&TempPte
);
1268 PdeOffset
= MiAddressToPteOffset(MmWorkingSetList
);
1269 HyperTable
[PdeOffset
] = TempPte
;
1271 /* Let go of the system PTE */
1272 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1274 /* Save the PTE address of the page directory itself */
1275 Pfn1
= MiGetPfnEntry(PdeIndex
);
1276 Pfn1
->PteAddress
= (PMMPTE
)PDE_BASE
;
1278 /* Insert us into the Mm process list */
1279 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1281 /* Get a PTE to map the page directory */
1282 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1283 ASSERT(PointerPte
!= NULL
);
1286 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1291 /* Set it dirty and map it */
1292 MI_MAKE_DIRTY_PAGE(&PdePte
);
1293 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1295 /* Now get the page directory (which we'll double map, so call it a page table */
1296 SystemTable
= MiPteToAddress(PointerPte
);
1298 /* Copy all the kernel mappings */
1299 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1300 RtlCopyMemory(&SystemTable
[PdeOffset
],
1301 MiAddressToPde(MmSystemRangeStart
),
1302 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1304 /* Now write the PTE/PDE entry for hyperspace itself */
1305 TempPte
= ValidKernelPte
;
1306 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1307 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1308 SystemTable
[PdeOffset
] = TempPte
;
1312 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1314 /* Now do the x86 trick of making the PDE a page table itself */
1315 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1316 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1317 SystemTable
[PdeOffset
] = TempPte
;
1319 /* Let go of the system PTE */
1320 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1322 /* Add the process to the session */
1323 MiSessionAddProcess(Process
);
1330 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1333 PMM_AVL_TABLE VadTree
;
1334 PETHREAD Thread
= PsGetCurrentThread();
1336 /* Only support this */
1337 ASSERT(Process
->AddressSpaceInitialized
== 2);
1339 /* Remove from the session */
1340 MiSessionRemoveProcess();
1342 /* Lock the process address space from changes */
1343 MmLockAddressSpace(&Process
->Vm
);
1344 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1346 /* VM is deleted now */
1347 Process
->VmDeleted
= TRUE
;
1348 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1350 /* Enumerate the VADs */
1351 VadTree
= &Process
->VadRoot
;
1352 while (VadTree
->NumberGenericTableElements
)
1354 /* Grab the current VAD */
1355 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1357 /* Lock the working set */
1358 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1360 /* Remove this VAD from the tree */
1361 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1362 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1364 /* Only regular VADs supported for now */
1365 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1367 /* Check if this is a section VAD */
1368 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1370 /* Remove the view */
1371 MiRemoveMappedView(Process
, Vad
);
1375 /* Delete the addresses */
1376 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1377 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1380 /* Release the working set */
1381 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1384 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1385 if (Vad
->u
.VadFlags
.Spare
== 1)
1387 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1388 Vad
->u
.VadFlags
.Spare
= 2;
1392 /* Free the VAD memory */
1396 /* Lock the working set */
1397 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1398 ASSERT(Process
->CloneRoot
== NULL
);
1399 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1401 /* Delete the shared user data section */
1402 MiDeleteVirtualAddresses(USER_SHARED_DATA
, USER_SHARED_DATA
, NULL
);
1404 /* Release the working set */
1405 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1407 /* Release the address space */
1408 MmUnlockAddressSpace(&Process
->Vm
);
1413 MmDeleteProcessAddressSpace2(IN PEPROCESS Process
)
1417 PFN_NUMBER PageFrameIndex
;
1419 //ASSERT(Process->CommitCharge == 0);
1421 /* Acquire the PFN lock */
1422 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1424 /* Check for fully initialized process */
1425 if (Process
->AddressSpaceInitialized
== 2)
1427 /* Map the working set page and its page table */
1428 Pfn1
= MiGetPfnEntry(Process
->WorkingSetPage
);
1429 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1432 MI_SET_PFN_DELETED(Pfn1
);
1433 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1434 MiDecrementShareCount(Pfn1
, Process
->WorkingSetPage
);
1435 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1436 MiReleaseSystemPtes(MiAddressToPte(Process
->Vm
.VmWorkingSetList
), 1, SystemPteSpace
);
1438 /* Now map hyperspace and its page table */
1439 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
;
1440 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1441 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1444 MI_SET_PFN_DELETED(Pfn1
);
1445 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1446 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1447 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1449 /* Finally, nuke the PDE itself */
1450 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
;
1451 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1452 MI_SET_PFN_DELETED(Pfn1
);
1453 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1454 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1456 /* Page table is now dead. Bye bye... */
1457 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1461 /* A partly-initialized process should never exit through here */
1465 /* Release the PFN lock */
1466 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1468 /* Drop a reference on the session */
1469 if (Process
->Session
) MiReleaseProcessReferenceToSessionDataPage(Process
->Session
);
1471 /* Clear out the PDE pages */
1472 Process
->Pcb
.DirectoryTableBase
[0] = 0;
1473 Process
->Pcb
.DirectoryTableBase
[1] = 0;
1476 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
1478 PMM_SESSION_SPACE MmSessionSpace
;
1479 PFN_NUMBER MiSessionDataPages
, MiSessionTagPages
, MiSessionTagSizePages
;
1480 PFN_NUMBER MiSessionBigPoolPages
, MiSessionCreateCharge
;
1481 KGUARDED_MUTEX MiSessionIdMutex
;
1482 LONG MmSessionDataPages
;
1483 PRTL_BITMAP MiSessionIdBitmap
;
1484 volatile LONG MiSessionLeaderExists
;
1488 MiInitializeSessionIds(VOID
)
1490 ULONG Size
, BitmapSize
;
1491 PFN_NUMBER TotalPages
;
1493 /* Setup the total number of data pages needed for the structure */
1494 TotalPages
= MI_SESSION_DATA_PAGES_MAXIMUM
;
1495 MiSessionDataPages
= ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE
)) >> PAGE_SHIFT
;
1496 ASSERT(MiSessionDataPages
<= MI_SESSION_DATA_PAGES_MAXIMUM
- 3);
1497 TotalPages
-= MiSessionDataPages
;
1499 /* Setup the number of pages needed for session pool tags */
1500 MiSessionTagSizePages
= 2;
1501 MiSessionBigPoolPages
= 1;
1502 MiSessionTagPages
= MiSessionTagSizePages
+ MiSessionBigPoolPages
;
1503 ASSERT(MiSessionTagPages
<= TotalPages
);
1504 ASSERT(MiSessionTagPages
< MI_SESSION_TAG_PAGES_MAXIMUM
);
1506 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
1507 MiSessionCreateCharge
= 1 + MiSessionDataPages
+ MiSessionTagPages
;
1509 /* Initialize the lock */
1510 KeInitializeGuardedMutex(&MiSessionIdMutex
);
1512 /* Allocate the bitmap */
1513 Size
= MI_INITIAL_SESSION_IDS
;
1514 BitmapSize
= ((Size
+ 31) / 32) * sizeof(ULONG
);
1515 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
1516 sizeof(RTL_BITMAP
) + BitmapSize
,
1518 if (MiSessionIdBitmap
)
1520 /* Free all the bits */
1521 RtlInitializeBitMap(MiSessionIdBitmap
,
1522 (PVOID
)(MiSessionIdBitmap
+ 1),
1524 RtlClearAllBits(MiSessionIdBitmap
);
1528 /* Die if we couldn't allocate the bitmap */
1529 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1530 MmNumberOfPhysicalPages
,
1531 MmLowestPhysicalPage
,
1532 MmHighestPhysicalPage
,
1539 MiSessionLeader(IN PEPROCESS Process
)
1543 /* Set the flag while under the expansion lock */
1544 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
1545 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
1546 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
1551 MmGetSessionId(IN PEPROCESS Process
)
1553 PMM_SESSION_SPACE SessionGlobal
;
1555 /* The session leader is always session zero */
1556 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
1558 /* Otherwise, get the session global, and read the session ID from it */
1559 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
1560 if (!SessionGlobal
) return 0;
1561 return SessionGlobal
->SessionId
;
1566 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal
)
1570 PFN_NUMBER PageFrameIndex
[MI_SESSION_DATA_PAGES_MAXIMUM
];
1574 /* Is there more than just this reference? If so, bail out */
1575 if (InterlockedDecrement(&SessionGlobal
->ProcessReferenceToSession
)) return;
1577 /* Get the session ID */
1578 SessionId
= SessionGlobal
->SessionId
;
1579 DPRINT1("Last process in sessino %d going down!!!\n", SessionId
);
1581 /* Free the session page tables */
1583 ExFreePoolWithTag(SessionGlobal
->PageTables
, 'tHmM');
1585 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal
));
1587 /* Capture the data page PFNs */
1588 PointerPte
= MiAddressToPte(SessionGlobal
);
1589 for (i
= 0; i
< MiSessionDataPages
; i
++)
1591 PageFrameIndex
[i
] = PFN_FROM_PTE(PointerPte
+ i
);
1595 MiReleaseSystemPtes(PointerPte
, MiSessionDataPages
, SystemPteSpace
);
1597 /* Mark them as deleted */
1598 for (i
= 0; i
< MiSessionDataPages
; i
++)
1600 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
1601 MI_SET_PFN_DELETED(Pfn1
);
1604 /* Loop every data page and drop a reference count */
1605 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1606 for (i
= 0; i
< MiSessionDataPages
; i
++)
1608 /* Sanity check that the page is correct, then decrement it */
1609 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
1610 ASSERT(Pfn1
->u2
.ShareCount
== 1);
1611 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 1);
1612 MiDecrementShareCount(Pfn1
, PageFrameIndex
[i
]);
1615 /* Done playing with pages, release the lock */
1616 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1618 /* Decrement the number of data pages */
1619 InterlockedDecrement(&MmSessionDataPages
);
1621 /* Free this session ID from the session bitmap */
1622 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1623 ASSERT(RtlCheckBit(MiSessionIdBitmap
, SessionId
));
1624 RtlClearBit(MiSessionIdBitmap
, SessionId
);
1625 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1630 MiSessionRemoveProcess(VOID
)
1632 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1634 /* If the process isn't already in a session, or if it's the leader... */
1635 if (!(CurrentProcess
->Flags
& PSF_PROCESS_IN_SESSION_BIT
) ||
1636 (CurrentProcess
->Vm
.Flags
.SessionLeader
))
1638 /* Then there's nothing to do */
1643 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
1645 /* Remove the process from the list ,and dereference the session */
1646 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
1647 //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
1648 //MiDereferenceSession();
1653 MiSessionAddProcess(IN PEPROCESS NewProcess
)
1655 PMM_SESSION_SPACE SessionGlobal
;
1657 /* The current process must already be in a session */
1658 if (!(PsGetCurrentProcess()->Flags
& PSF_PROCESS_IN_SESSION_BIT
)) return;
1661 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
1663 /* Get the global session */
1664 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
1666 /* Increment counters */
1667 InterlockedIncrement((PLONG
)&SessionGlobal
->ReferenceCount
);
1668 InterlockedIncrement(&SessionGlobal
->ResidentProcessCount
);
1669 InterlockedIncrement(&SessionGlobal
->ProcessReferenceToSession
);
1671 /* Set the session pointer */
1672 ASSERT(NewProcess
->Session
== NULL
);
1673 NewProcess
->Session
= SessionGlobal
;
1675 /* Insert it into the process list */
1676 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
1677 //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
1680 PspSetProcessFlag(NewProcess
, PSF_PROCESS_IN_SESSION_BIT
);
1685 MiSessionInitializeWorkingSetList(VOID
)
1688 PMMPTE PointerPte
, PointerPde
;
1691 PFN_NUMBER PageFrameIndex
;
1692 PMM_SESSION_SPACE SessionGlobal
;
1693 BOOLEAN AllocatedPageTable
;
1694 PMMWSL WorkingSetList
;
1696 /* Get pointers to session global and the session working set list */
1697 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
1698 WorkingSetList
= (PMMWSL
)MiSessionSpaceWs
;
1700 /* Fill out the two pointers */
1701 MmSessionSpace
->Vm
.VmWorkingSetList
= WorkingSetList
;
1702 MmSessionSpace
->Wsle
= (PMMWSLE
)WorkingSetList
->UsedPageTableEntries
;
1704 /* Get the PDE for the working set, and check if it's already allocated */
1705 PointerPde
= MiAddressToPde(WorkingSetList
);
1706 if (PointerPde
->u
.Hard
.Valid
== 1)
1708 /* Nope, we'll have to do it */
1709 ASSERT(PointerPde
->u
.Hard
.Global
== 0);
1710 AllocatedPageTable
= FALSE
;
1714 /* Yep, that makes our job easier */
1715 AllocatedPageTable
= TRUE
;
1718 /* Get the PTE for the working set */
1719 PointerPte
= MiAddressToPte(WorkingSetList
);
1721 /* Initialize the working set lock, and lock the PFN database */
1722 ExInitializePushLock(&SessionGlobal
->Vm
.WorkingSetMutex
);
1723 //MmLockPageableSectionByHandle(ExPageLockHandle);
1724 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1726 /* Check if we need a page table */
1727 if (AllocatedPageTable
== TRUE
)
1729 /* Get a zeroed colored zero page */
1730 Color
= MI_GET_NEXT_COLOR();
1731 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
1732 if (!PageFrameIndex
)
1734 /* No zero pages, grab a free one */
1735 PageFrameIndex
= MiRemoveAnyPage(Color
);
1737 /* Zero it outside the PFN lock */
1738 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1739 MiZeroPhysicalPage(PageFrameIndex
);
1740 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1743 /* Write a valid PDE for it */
1744 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
1745 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
1746 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1748 /* Add this into the list */
1749 Index
= ((ULONG_PTR
)WorkingSetList
- (ULONG_PTR
)MmSessionBase
) >> 22;
1751 MmSessionSpace
->PageTables
[Index
] = TempPte
;
1753 /* Initialize the page directory page, and now zero the working set list itself */
1754 MiInitializePfnForOtherProcess(PageFrameIndex
,
1756 MmSessionSpace
->SessionPageDirectoryIndex
);
1757 KeZeroPages(PointerPte
, PAGE_SIZE
);
1760 /* Get a zeroed colored zero page */
1761 Color
= MI_GET_NEXT_COLOR();
1762 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
1763 if (!PageFrameIndex
)
1765 /* No zero pages, grab a free one */
1766 PageFrameIndex
= MiRemoveAnyPage(Color
);
1768 /* Zero it outside the PFN lock */
1769 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1770 MiZeroPhysicalPage(PageFrameIndex
);
1771 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1774 /* Write a valid PTE for it */
1775 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
1776 TempPte
.u
.Hard
.Dirty
= TRUE
;
1777 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
1779 /* Initialize the working set list page */
1780 MiInitializePfnAndMakePteValid(PageFrameIndex
, PointerPte
, TempPte
);
1782 /* Now we can release the PFN database lock */
1783 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1785 /* Fill out the working set structure */
1786 MmSessionSpace
->Vm
.Flags
.SessionSpace
= 1;
1787 MmSessionSpace
->Vm
.MinimumWorkingSetSize
= 20;
1788 MmSessionSpace
->Vm
.MaximumWorkingSetSize
= 384;
1789 WorkingSetList
->LastEntry
= 20;
1790 WorkingSetList
->HashTable
= NULL
;
1791 WorkingSetList
->HashTableSize
= 0;
1792 WorkingSetList
->Wsle
= MmSessionSpace
->Wsle
;
1794 /* FIXME: Handle list insertions */
1795 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
1796 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
1797 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Flink
== NULL
);
1798 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Blink
== NULL
);
1800 /* All done, return */
1801 //MmUnlockPageableImageSection(ExPageLockHandle);
1802 return STATUS_SUCCESS
;
1807 MiSessionCreateInternal(OUT PULONG SessionId
)
1809 PEPROCESS Process
= PsGetCurrentProcess();
1810 ULONG NewFlags
, Flags
, Size
, i
, Color
;
1812 PMMPTE PointerPte
, PageTables
, SessionPte
;
1814 PMM_SESSION_SPACE SessionGlobal
;
1818 PFN_NUMBER SessionPageDirIndex
;
1819 PFN_NUMBER TagPage
[MI_SESSION_TAG_PAGES_MAXIMUM
];
1820 PFN_NUMBER DataPage
[MI_SESSION_DATA_PAGES_MAXIMUM
];
1822 /* This should not exist yet */
1823 ASSERT(MmIsAddressValid(MmSessionSpace
) == FALSE
);
1825 /* Loop so we can set the session-is-creating flag */
1826 Flags
= Process
->Flags
;
1829 /* Check if it's already set */
1830 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
1833 DPRINT1("Lost session race\n");
1834 return STATUS_ALREADY_COMMITTED
;
1837 /* Now try to set it */
1838 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
1839 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
1841 if (NewFlags
== Flags
) break;
1843 /* It changed, try again */
1847 /* Now we should own the flag */
1848 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1851 * Session space covers everything from 0xA0000000 to 0xC0000000.
1852 * Allocate enough page tables to describe the entire region
1854 Size
= (0x20000000 / PDE_MAPPED_VA
) * sizeof(MMPTE
);
1855 PageTables
= ExAllocatePoolWithTag(NonPagedPool
, Size
, 'tHmM');
1856 ASSERT(PageTables
!= NULL
);
1857 RtlZeroMemory(PageTables
, Size
);
1859 /* Lock the session ID creation mutex */
1860 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1862 /* Allocate a new Session ID */
1863 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
1864 if (*SessionId
== 0xFFFFFFFF)
1866 /* We ran out of session IDs, we should expand */
1867 DPRINT1("Too many sessions created. Expansion not yet supported\n");
1868 ExFreePoolWithTag(PageTables
, 'tHmM');
1869 return STATUS_NO_MEMORY
;
1872 /* Unlock the session ID creation mutex */
1873 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1875 /* Reserve the global PTEs */
1876 SessionPte
= MiReserveSystemPtes(MiSessionDataPages
, SystemPteSpace
);
1877 ASSERT(SessionPte
!= NULL
);
1879 /* Acquire the PFN lock while we set everything up */
1880 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1882 /* Loop the global PTEs */
1883 TempPte
.u
.Long
= ValidKernelPte
.u
.Long
;
1884 for (i
= 0; i
< MiSessionDataPages
; i
++)
1886 /* Get a zeroed colored zero page */
1887 Color
= MI_GET_NEXT_COLOR();
1888 DataPage
[i
] = MiRemoveZeroPageSafe(Color
);
1891 /* No zero pages, grab a free one */
1892 DataPage
[i
] = MiRemoveAnyPage(Color
);
1894 /* Zero it outside the PFN lock */
1895 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1896 MiZeroPhysicalPage(DataPage
[i
]);
1897 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1900 /* Fill the PTE out */
1901 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1902 MI_WRITE_VALID_PTE(SessionPte
+ i
, TempPte
);
1905 /* Set the pointer to global space */
1906 SessionGlobal
= MiPteToAddress(SessionPte
);
1908 /* Get a zeroed colored zero page */
1909 Color
= MI_GET_NEXT_COLOR();
1910 SessionPageDirIndex
= MiRemoveZeroPageSafe(Color
);
1911 if (!SessionPageDirIndex
)
1913 /* No zero pages, grab a free one */
1914 SessionPageDirIndex
= MiRemoveAnyPage(Color
);
1916 /* Zero it outside the PFN lock */
1917 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1918 MiZeroPhysicalPage(SessionPageDirIndex
);
1919 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1922 /* Fill the PTE out */
1923 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
1924 TempPte
.u
.Hard
.PageFrameNumber
= SessionPageDirIndex
;
1926 /* Setup, allocate, fill out the MmSessionSpace PTE */
1927 PointerPde
= MiAddressToPde(MmSessionSpace
);
1928 ASSERT(PointerPde
->u
.Long
== 0);
1929 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1930 MiInitializePfnForOtherProcess(SessionPageDirIndex
,
1932 SessionPageDirIndex
);
1933 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex
)->u1
.WsIndex
== 0);
1935 /* Loop all the local PTEs for it */
1936 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
1937 PointerPte
= MiAddressToPte(MmSessionSpace
);
1938 for (i
= 0; i
< MiSessionDataPages
; i
++)
1940 /* And fill them out */
1941 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1942 MiInitializePfnAndMakePteValid(DataPage
[i
], PointerPte
+ i
, TempPte
);
1943 ASSERT(MI_PFN_ELEMENT(DataPage
[i
])->u1
.WsIndex
== 0);
1946 /* Finally loop all of the session pool tag pages */
1947 for (i
= 0; i
< MiSessionTagPages
; i
++)
1949 /* Grab a zeroed colored page */
1950 Color
= MI_GET_NEXT_COLOR();
1951 TagPage
[i
] = MiRemoveZeroPageSafe(Color
);
1954 /* No zero pages, grab a free one */
1955 TagPage
[i
] = MiRemoveAnyPage(Color
);
1957 /* Zero it outside the PFN lock */
1958 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1959 MiZeroPhysicalPage(TagPage
[i
]);
1960 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1963 /* Fill the PTE out */
1964 TempPte
.u
.Hard
.PageFrameNumber
= TagPage
[i
];
1965 MiInitializePfnAndMakePteValid(TagPage
[i
],
1966 PointerPte
+ MiSessionDataPages
+ i
,
1970 /* PTEs have been setup, release the PFN lock */
1971 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1973 /* Fill out the session space structure now */
1974 MmSessionSpace
->GlobalVirtualAddress
= SessionGlobal
;
1975 MmSessionSpace
->ReferenceCount
= 1;
1976 MmSessionSpace
->ResidentProcessCount
= 1;
1977 MmSessionSpace
->u
.LongFlags
= 0;
1978 MmSessionSpace
->SessionId
= *SessionId
;
1979 MmSessionSpace
->LocaleId
= PsDefaultSystemLocaleId
;
1980 MmSessionSpace
->SessionPageDirectoryIndex
= SessionPageDirIndex
;
1981 MmSessionSpace
->Color
= Color
;
1982 MmSessionSpace
->NonPageablePages
= MiSessionCreateCharge
;
1983 MmSessionSpace
->CommittedPages
= MiSessionCreateCharge
;
1985 MmSessionSpace
->PageTables
= PageTables
;
1986 MmSessionSpace
->PageTables
[PointerPde
- MiAddressToPde(MmSessionBase
)] = *PointerPde
;
1988 InitializeListHead(&MmSessionSpace
->ImageList
);
1989 DPRINT1("Session %d is ready to go: 0x%p 0x%p, %lx 0x%p\n",
1990 *SessionId
, MmSessionSpace
, SessionGlobal
, SessionPageDirIndex
, PageTables
);
1992 /* Initialize session pool */
1993 //Status = MiInitializeSessionPool();
1994 Status
= STATUS_SUCCESS
;
1995 ASSERT(NT_SUCCESS(Status
) == TRUE
);
1997 /* Initialize system space */
1998 Result
= MiInitializeSystemSpaceMap(&SessionGlobal
->Session
);
1999 ASSERT(Result
== TRUE
);
2001 /* Initialize the process list, make sure the workign set list is empty */
2002 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
2003 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
2004 InitializeListHead(&SessionGlobal
->ProcessList
);
2006 /* We're done, clear the flag */
2007 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
2008 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
2010 /* Insert the process into the session */
2011 ASSERT(Process
->Session
== NULL
);
2012 ASSERT(SessionGlobal
->ProcessReferenceToSession
== 0);
2013 SessionGlobal
->ProcessReferenceToSession
= 1;
2016 InterlockedIncrement(&MmSessionDataPages
);
2017 return STATUS_SUCCESS
;
2022 MmSessionCreate(OUT PULONG SessionId
)
2024 PEPROCESS Process
= PsGetCurrentProcess();
2025 ULONG SessionLeaderExists
;
2028 /* Fail if the process is already in a session */
2029 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
2031 DPRINT1("Process already in session\n");
2032 return STATUS_ALREADY_COMMITTED
;
2035 /* Check if the process is already the session leader */
2036 if (!Process
->Vm
.Flags
.SessionLeader
)
2038 /* Atomically set it as the leader */
2039 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
2040 if (SessionLeaderExists
)
2042 DPRINT1("Session leader race\n");
2043 return STATUS_INVALID_SYSTEM_SERVICE
;
2046 /* Do the work required to upgrade him */
2047 MiSessionLeader(Process
);
2050 /* Create the session */
2051 KeEnterCriticalRegion();
2052 Status
= MiSessionCreateInternal(SessionId
);
2053 if (!NT_SUCCESS(Status
))
2055 KeLeaveCriticalRegion();
2059 /* Set up the session working set */
2060 Status
= MiSessionInitializeWorkingSetList();
2061 if (!NT_SUCCESS(Status
))
2064 //MiDereferenceSession();
2066 KeLeaveCriticalRegion();
2071 KeLeaveCriticalRegion();
2073 /* Set and assert the flags, and return */
2074 MmSessionSpace
->u
.Flags
.Initialized
= 1;
2075 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
2076 ASSERT(MiSessionLeaderExists
== 1);
2082 MmSessionDelete(IN ULONG SessionId
)
2084 PEPROCESS Process
= PsGetCurrentProcess();
2086 /* Process must be in a session */
2087 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
2089 DPRINT1("Not in a session!\n");
2090 return STATUS_UNABLE_TO_FREE_VM
;
2093 /* It must be the session leader */
2094 if (!Process
->Vm
.Flags
.SessionLeader
)
2096 DPRINT1("Not a session leader!\n");
2097 return STATUS_UNABLE_TO_FREE_VM
;
2100 /* Remove one reference count */
2101 KeEnterCriticalRegion();
2103 KeLeaveCriticalRegion();
2106 return STATUS_SUCCESS
;
2109 /* SYSTEM CALLS ***************************************************************/
2113 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
2114 IN OUT PULONG_PTR NumberOfPages
,
2115 IN OUT PULONG_PTR UserPfnArray
)
2118 return STATUS_NOT_IMPLEMENTED
;
2123 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
2124 IN ULONG_PTR NumberOfPages
,
2125 IN OUT PULONG_PTR UserPfnArray
)
2128 return STATUS_NOT_IMPLEMENTED
;
2133 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
2134 IN ULONG_PTR NumberOfPages
,
2135 IN OUT PULONG_PTR UserPfnArray
)
2138 return STATUS_NOT_IMPLEMENTED
;
2143 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
2144 IN OUT PULONG_PTR NumberOfPages
,
2145 IN OUT PULONG_PTR UserPfnArray
)
2148 return STATUS_NOT_IMPLEMENTED
;