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;
697 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
698 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
703 MmGetSessionId(Process
);
705 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
711 _SEH2_YIELD(return _SEH2_GetExceptionCode());
716 // Use SEH in case we can't load the image
723 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
724 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
732 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
742 // Use SEH in case we can't load the headers
747 // Get the Image Config Data too
749 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
751 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
758 ProbeForRead(ImageConfigData
,
759 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
764 // Write subsystem data
766 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
767 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
768 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
771 // Check for version data
773 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
776 // Extract values and write them
778 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
779 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
780 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
781 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
783 /* Process CSD version override */
784 if ((ImageConfigData
) && (ImageConfigData
->CSDVersion
))
786 /* Take the value from the image configuration directory */
787 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
791 /* Process optional process affinity mask override */
792 if ((ImageConfigData
) && (ImageConfigData
->ProcessAffinityMask
))
794 /* Take the value from the image configuration directory */
795 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
799 // Check if this is a UP image
800 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
803 // Force it to use CPU 0
805 /* FIXME: this should use the MmRotatingUniprocessorNumber */
806 Peb
->ImageProcessAffinityMask
= 0;
811 // Whatever was configured
813 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
816 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
822 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
828 // Detach from the Process
832 return STATUS_SUCCESS
;
837 MmCreateTeb(IN PEPROCESS Process
,
838 IN PCLIENT_ID ClientId
,
839 IN PINITIAL_TEB InitialTeb
,
843 NTSTATUS Status
= STATUS_SUCCESS
;
849 KeAttachProcess(&Process
->Pcb
);
854 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
855 ASSERT(NT_SUCCESS(Status
));
858 // Use SEH in case we can't load the TEB
863 // Initialize the PEB
865 RtlZeroMemory(Teb
, sizeof(TEB
));
871 Teb
->NtTib
.ExceptionList
= NULL
;
873 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
875 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
878 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
880 Teb
->NtTib
.Version
= 30 << 8;
885 Teb
->ClientId
= *ClientId
;
886 Teb
->RealClientId
= *ClientId
;
887 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
888 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
891 // Check if we have a grandparent TEB
893 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
894 (InitialTeb
->PreviousStackLimit
== NULL
))
897 // Use initial TEB values
899 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
900 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
901 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
906 // Use grandparent TEB values
908 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
909 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
913 // Initialize the static unicode string
915 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
916 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
923 Status
= _SEH2_GetExceptionCode();
937 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess
)
943 /* Setup some bogus list data */
944 MmWorkingSetList
->LastEntry
= CurrentProcess
->Vm
.MinimumWorkingSetSize
;
945 MmWorkingSetList
->HashTable
= NULL
;
946 MmWorkingSetList
->HashTableSize
= 0;
947 MmWorkingSetList
->NumberOfImageWaiters
= 0;
948 MmWorkingSetList
->Wsle
= (PVOID
)0xDEADBABE;
949 MmWorkingSetList
->VadBitMapHint
= 1;
950 MmWorkingSetList
->HashTableStart
= (PVOID
)0xBADAB00B;
951 MmWorkingSetList
->HighestPermittedHashAddress
= (PVOID
)0xCAFEBABE;
952 MmWorkingSetList
->FirstFree
= 1;
953 MmWorkingSetList
->FirstDynamic
= 2;
954 MmWorkingSetList
->NextSlot
= 3;
955 MmWorkingSetList
->LastInitializedWsle
= 4;
957 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
958 Pfn1
= MiGetPfnEntry(CurrentProcess
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
);
959 ASSERT(Pfn1
->u4
.PteFrame
== MiGetPfnEntryIndex(Pfn1
));
960 Pfn1
->u1
.Event
= (PKEVENT
)CurrentProcess
;
962 /* Map the process working set in kernel space */
963 sysPte
= MiReserveSystemPtes(1, SystemPteSpace
);
964 MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte
, sysPte
, MM_READWRITE
, CurrentProcess
->WorkingSetPage
);
965 MI_WRITE_VALID_PTE(sysPte
, tempPte
);
966 CurrentProcess
->Vm
.VmWorkingSetList
= MiPteToAddress(sysPte
);
971 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
972 IN PEPROCESS ProcessClone OPTIONAL
,
973 IN PVOID Section OPTIONAL
,
975 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
977 NTSTATUS Status
= STATUS_SUCCESS
;
980 PROS_SECTION_OBJECT SectionObject
= Section
;
984 PFN_NUMBER PageFrameNumber
;
985 UNICODE_STRING FileName
;
991 /* We should have a PDE */
992 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
993 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
995 /* Attach to the process */
996 KeAttachProcess(&Process
->Pcb
);
998 /* The address space should now been in phase 1 or 0 */
999 ASSERT(Process
->AddressSpaceInitialized
<= 1);
1000 Process
->AddressSpaceInitialized
= 2;
1002 /* Initialize the Addresss Space lock */
1003 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1004 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1006 /* Initialize AVL tree */
1007 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1008 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1010 /* Lock PFN database */
1011 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1013 /* Setup the PFN for the PDE base of this process */
1015 PointerPte
= MiAddressToPte(PXE_BASE
);
1017 PointerPte
= MiAddressToPte(PDE_BASE
);
1019 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1020 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == PageFrameNumber
* PAGE_SIZE
);
1021 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1023 /* Do the same for hyperspace */
1025 PointerPde
= MiAddressToPxe((PVOID
)HYPER_SPACE
);
1027 PointerPde
= MiAddressToPde(HYPER_SPACE
);
1029 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
1030 //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
1031 MiInitializePfn(PageFrameNumber
, (PMMPTE
)PointerPde
, TRUE
);
1033 /* Setup the PFN for the PTE for the working set */
1034 PointerPte
= MiAddressToPte(MI_WORKING_SET_LIST
);
1035 MI_MAKE_HARDWARE_PTE(&TempPte
, PointerPte
, MM_READWRITE
, 0);
1036 ASSERT(PointerPte
->u
.Long
!= 0);
1037 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1038 MI_WRITE_INVALID_PTE(PointerPte
, DemandZeroPte
);
1039 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1040 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameNumber
;
1041 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1043 /* Now initialize the working set list */
1044 MiInitializeWorkingSetList(Process
);
1047 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1049 /* Release PFN lock */
1050 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1052 /* Lock the VAD, ARM3-owned ranges away */
1053 MiRosTakeOverSharedUserPage(Process
);
1055 /* Check if there's a Section Object */
1058 /* Determine the image file name and save it to EPROCESS */
1059 FileName
= SectionObject
->FileObject
->FileName
;
1060 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
1061 if (FileName
.Buffer
)
1063 /* Loop the file name*/
1064 while (Source
> FileName
.Buffer
)
1066 /* Make sure this isn't a backslash */
1067 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
1069 /* If so, stop it here */
1075 /* Otherwise, keep going */
1081 /* Copy the to the process and truncate it to 15 characters if necessary */
1082 Destination
= Process
->ImageFileName
;
1083 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
1084 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
1085 *Destination
= ANSI_NULL
;
1087 /* Check if caller wants an audit name */
1090 /* Setup the audit name */
1091 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
1094 if (!NT_SUCCESS(Status
))
1102 /* Map the section */
1103 Status
= MmMapViewOfSection(Section
,
1114 /* Save the pointer */
1115 Process
->SectionBaseAddress
= ImageBase
;
1118 /* Be nice and detach */
1121 /* Return status to caller */
1128 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1129 IN PULONG_PTR DirectoryTableBase
)
1131 /* Share the directory base with the idle process */
1132 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1133 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1135 /* Initialize the Addresss Space */
1136 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1137 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1138 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1139 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1140 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1142 /* Use idle process Working set */
1143 Process
->Vm
.VmWorkingSetList
= PsGetCurrentProcess()->Vm
.VmWorkingSetList
;
1146 Process
->HasAddressSpace
= TRUE
;//??
1147 return STATUS_SUCCESS
;
1153 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1155 /* Lock the VAD, ARM3-owned ranges away */
1156 MiRosTakeOverSharedUserPage(Process
);
1157 return STATUS_SUCCESS
;
1161 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1164 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1165 IN PEPROCESS Process
,
1166 OUT PULONG_PTR DirectoryTableBase
)
1169 PFN_NUMBER PdeIndex
, HyperIndex
, WsListIndex
;
1171 MMPTE TempPte
, PdePte
;
1173 PMMPTE SystemTable
, HyperTable
;
1177 /* Choose a process color */
1178 Process
->NextPageColor
= (USHORT
)RtlRandom(&MmProcessColorSeed
);
1180 /* Setup the hyperspace lock */
1181 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1183 /* Lock PFN database */
1184 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1186 /* Get a zero page for the PDE, if possible */
1187 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1188 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1189 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1192 /* No zero pages, grab a free one */
1193 PdeIndex
= MiRemoveAnyPage(Color
);
1195 /* Zero it outside the PFN lock */
1196 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1197 MiZeroPhysicalPage(PdeIndex
);
1198 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1201 /* Get a zero page for hyperspace, if possible */
1202 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1203 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1204 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1207 /* No zero pages, grab a free one */
1208 HyperIndex
= MiRemoveAnyPage(Color
);
1210 /* Zero it outside the PFN lock */
1211 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1212 MiZeroPhysicalPage(HyperIndex
);
1213 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1216 /* Get a zero page for the woring set list, if possible */
1217 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
1218 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1219 WsListIndex
= MiRemoveZeroPageSafe(Color
);
1222 /* No zero pages, grab a free one */
1223 WsListIndex
= MiRemoveAnyPage(Color
);
1225 /* Zero it outside the PFN lock */
1226 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1227 MiZeroPhysicalPage(WsListIndex
);
1231 /* Release the PFN lock */
1232 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1235 /* Switch to phase 1 initialization */
1236 ASSERT(Process
->AddressSpaceInitialized
== 0);
1237 Process
->AddressSpaceInitialized
= 1;
1239 /* Set the base directory pointers */
1240 Process
->WorkingSetPage
= WsListIndex
;
1241 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1242 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1244 /* Make sure we don't already have a page directory setup */
1245 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1247 /* Get a PTE to map hyperspace */
1248 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1249 ASSERT(PointerPte
!= NULL
);
1252 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1257 /* Set it dirty and map it */
1258 MI_MAKE_DIRTY_PAGE(&PdePte
);
1259 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1261 /* Now get hyperspace's page table */
1262 HyperTable
= MiPteToAddress(PointerPte
);
1264 /* Now write the PTE/PDE entry for the working set list index itself */
1265 TempPte
= ValidKernelPte
;
1266 TempPte
.u
.Hard
.PageFrameNumber
= WsListIndex
;
1267 /* Hyperspace is local */
1268 MI_MAKE_LOCAL_PAGE(&TempPte
);
1269 PdeOffset
= MiAddressToPteOffset(MmWorkingSetList
);
1270 HyperTable
[PdeOffset
] = TempPte
;
1272 /* Let go of the system PTE */
1273 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1275 /* Save the PTE address of the page directory itself */
1276 Pfn1
= MiGetPfnEntry(PdeIndex
);
1277 Pfn1
->PteAddress
= (PMMPTE
)PDE_BASE
;
1279 /* Insert us into the Mm process list */
1280 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1282 /* Get a PTE to map the page directory */
1283 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1284 ASSERT(PointerPte
!= NULL
);
1287 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1292 /* Set it dirty and map it */
1293 MI_MAKE_DIRTY_PAGE(&PdePte
);
1294 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1296 /* Now get the page directory (which we'll double map, so call it a page table */
1297 SystemTable
= MiPteToAddress(PointerPte
);
1299 /* Copy all the kernel mappings */
1300 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1301 RtlCopyMemory(&SystemTable
[PdeOffset
],
1302 MiAddressToPde(MmSystemRangeStart
),
1303 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1305 /* Now write the PTE/PDE entry for hyperspace itself */
1306 TempPte
= ValidKernelPte
;
1307 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1308 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1309 SystemTable
[PdeOffset
] = TempPte
;
1313 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1315 /* Now do the x86 trick of making the PDE a page table itself */
1316 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1317 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1318 SystemTable
[PdeOffset
] = TempPte
;
1320 /* Let go of the system PTE */
1321 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1323 /* Add the process to the session */
1324 MiSessionAddProcess(Process
);
1331 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1334 PMM_AVL_TABLE VadTree
;
1335 PETHREAD Thread
= PsGetCurrentThread();
1337 /* Only support this */
1338 ASSERT(Process
->AddressSpaceInitialized
== 2);
1340 /* Remove from the session */
1341 MiSessionRemoveProcess();
1343 /* Lock the process address space from changes */
1344 MmLockAddressSpace(&Process
->Vm
);
1345 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1347 /* VM is deleted now */
1348 Process
->VmDeleted
= TRUE
;
1349 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1351 /* Enumerate the VADs */
1352 VadTree
= &Process
->VadRoot
;
1353 while (VadTree
->NumberGenericTableElements
)
1355 /* Grab the current VAD */
1356 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1358 /* Lock the working set */
1359 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1361 /* Remove this VAD from the tree */
1362 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1363 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1365 /* Only regular VADs supported for now */
1366 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1368 /* Check if this is a section VAD */
1369 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1371 /* Remove the view */
1372 MiRemoveMappedView(Process
, Vad
);
1376 /* Delete the addresses */
1377 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1378 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1381 /* Release the working set */
1382 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1385 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1386 if (Vad
->u
.VadFlags
.Spare
== 1)
1388 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1389 Vad
->u
.VadFlags
.Spare
= 2;
1393 /* Free the VAD memory */
1397 /* Lock the working set */
1398 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1399 ASSERT(Process
->CloneRoot
== NULL
);
1400 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1402 /* Delete the shared user data section */
1403 MiDeleteVirtualAddresses(USER_SHARED_DATA
, USER_SHARED_DATA
, NULL
);
1405 /* Release the working set */
1406 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1408 /* Release the address space */
1409 MmUnlockAddressSpace(&Process
->Vm
);
1414 MmDeleteProcessAddressSpace2(IN PEPROCESS Process
)
1418 PFN_NUMBER PageFrameIndex
;
1420 //ASSERT(Process->CommitCharge == 0);
1422 /* Acquire the PFN lock */
1423 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1425 /* Check for fully initialized process */
1426 if (Process
->AddressSpaceInitialized
== 2)
1428 /* Map the working set page and its page table */
1429 Pfn1
= MiGetPfnEntry(Process
->WorkingSetPage
);
1430 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1433 MI_SET_PFN_DELETED(Pfn1
);
1434 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1435 MiDecrementShareCount(Pfn1
, Process
->WorkingSetPage
);
1436 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1437 MiReleaseSystemPtes(MiAddressToPte(Process
->Vm
.VmWorkingSetList
), 1, SystemPteSpace
);
1439 /* Now map hyperspace and its page table */
1440 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
;
1441 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1442 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1445 MI_SET_PFN_DELETED(Pfn1
);
1446 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1447 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1448 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1450 /* Finally, nuke the PDE itself */
1451 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
;
1452 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1453 MI_SET_PFN_DELETED(Pfn1
);
1454 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1455 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1457 /* Page table is now dead. Bye bye... */
1458 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1462 /* A partly-initialized process should never exit through here */
1466 /* Release the PFN lock */
1467 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1469 /* Drop a reference on the session */
1470 if (Process
->Session
) MiReleaseProcessReferenceToSessionDataPage(Process
->Session
);
1472 /* Clear out the PDE pages */
1473 Process
->Pcb
.DirectoryTableBase
[0] = 0;
1474 Process
->Pcb
.DirectoryTableBase
[1] = 0;
1477 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
1479 PMM_SESSION_SPACE MmSessionSpace
;
1480 PFN_NUMBER MiSessionDataPages
, MiSessionTagPages
, MiSessionTagSizePages
;
1481 PFN_NUMBER MiSessionBigPoolPages
, MiSessionCreateCharge
;
1482 KGUARDED_MUTEX MiSessionIdMutex
;
1483 LONG MmSessionDataPages
;
1484 PRTL_BITMAP MiSessionIdBitmap
;
1485 volatile LONG MiSessionLeaderExists
;
1489 MiInitializeSessionIds(VOID
)
1491 ULONG Size
, BitmapSize
;
1492 PFN_NUMBER TotalPages
;
1494 /* Setup the total number of data pages needed for the structure */
1495 TotalPages
= MI_SESSION_DATA_PAGES_MAXIMUM
;
1496 MiSessionDataPages
= ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE
)) >> PAGE_SHIFT
;
1497 ASSERT(MiSessionDataPages
<= MI_SESSION_DATA_PAGES_MAXIMUM
- 3);
1498 TotalPages
-= MiSessionDataPages
;
1500 /* Setup the number of pages needed for session pool tags */
1501 MiSessionTagSizePages
= 2;
1502 MiSessionBigPoolPages
= 1;
1503 MiSessionTagPages
= MiSessionTagSizePages
+ MiSessionBigPoolPages
;
1504 ASSERT(MiSessionTagPages
<= TotalPages
);
1505 ASSERT(MiSessionTagPages
< MI_SESSION_TAG_PAGES_MAXIMUM
);
1507 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
1508 MiSessionCreateCharge
= 1 + MiSessionDataPages
+ MiSessionTagPages
;
1510 /* Initialize the lock */
1511 KeInitializeGuardedMutex(&MiSessionIdMutex
);
1513 /* Allocate the bitmap */
1514 Size
= MI_INITIAL_SESSION_IDS
;
1515 BitmapSize
= ((Size
+ 31) / 32) * sizeof(ULONG
);
1516 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
1517 sizeof(RTL_BITMAP
) + BitmapSize
,
1519 if (MiSessionIdBitmap
)
1521 /* Free all the bits */
1522 RtlInitializeBitMap(MiSessionIdBitmap
,
1523 (PVOID
)(MiSessionIdBitmap
+ 1),
1525 RtlClearAllBits(MiSessionIdBitmap
);
1529 /* Die if we couldn't allocate the bitmap */
1530 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1531 MmNumberOfPhysicalPages
,
1532 MmLowestPhysicalPage
,
1533 MmHighestPhysicalPage
,
1540 MiSessionLeader(IN PEPROCESS Process
)
1544 /* Set the flag while under the expansion lock */
1545 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
1546 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
1547 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
1552 MmGetSessionId(IN PEPROCESS Process
)
1554 PMM_SESSION_SPACE SessionGlobal
;
1556 /* The session leader is always session zero */
1557 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
1559 /* Otherwise, get the session global, and read the session ID from it */
1560 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
1561 if (!SessionGlobal
) return 0;
1562 return SessionGlobal
->SessionId
;
1567 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal
)
1571 PFN_NUMBER PageFrameIndex
[MI_SESSION_DATA_PAGES_MAXIMUM
];
1575 /* Is there more than just this reference? If so, bail out */
1576 if (InterlockedDecrement(&SessionGlobal
->ProcessReferenceToSession
)) return;
1578 /* Get the session ID */
1579 SessionId
= SessionGlobal
->SessionId
;
1580 DPRINT1("Last process in sessino %d going down!!!\n", SessionId
);
1582 /* Free the session page tables */
1583 ExFreePool(SessionGlobal
->PageTables
);
1584 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal
));
1586 /* Capture the data page PFNs */
1587 PointerPte
= MiAddressToPte(SessionGlobal
);
1588 for (i
= 0; i
< MiSessionDataPages
; i
++)
1590 PageFrameIndex
[i
] = PFN_FROM_PTE(PointerPte
+ i
);
1594 MiReleaseSystemPtes(PointerPte
, MiSessionDataPages
, SystemPteSpace
);
1596 /* Mark them as deleted */
1597 for (i
= 0; i
< MiSessionDataPages
; i
++)
1599 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
1600 MI_SET_PFN_DELETED(Pfn1
);
1603 /* Loop every data page and drop a reference count */
1604 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1605 for (i
= 0; i
< MiSessionDataPages
; i
++)
1607 /* Sanity check that the page is correct, then decrement it */
1608 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
1609 ASSERT(Pfn1
->u2
.ShareCount
== 1);
1610 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 1);
1611 MiDecrementShareCount(Pfn1
, PageFrameIndex
[i
]);
1614 /* Done playing with pages, release the lock */
1615 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1617 /* Decrement the number of data pages */
1618 InterlockedDecrement(&MmSessionDataPages
);
1620 /* Free this session ID from the session bitmap */
1621 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1622 ASSERT(RtlCheckBit(MiSessionIdBitmap
, SessionId
));
1623 RtlClearBit(MiSessionIdBitmap
, SessionId
);
1624 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1629 MiSessionRemoveProcess(VOID
)
1631 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1633 /* If the process isn't already in a session, or if it's the leader... */
1634 if (!(CurrentProcess
->Flags
& PSF_PROCESS_IN_SESSION_BIT
) ||
1635 (CurrentProcess
->Vm
.Flags
.SessionLeader
))
1637 /* Then there's nothing to do */
1642 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
1644 /* Remove the process from the list ,and dereference the session */
1645 RemoveEntryList(&CurrentProcess
->SessionProcessLinks
);
1646 //MiDereferenceSession();
1651 MiSessionAddProcess(IN PEPROCESS NewProcess
)
1653 PMM_SESSION_SPACE SessionGlobal
;
1655 /* The current process must already be in a session */
1656 if (!(PsGetCurrentProcess()->Flags
& PSF_PROCESS_IN_SESSION_BIT
)) return;
1659 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
1661 /* Get the global session */
1662 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
1664 /* Increment counters */
1665 InterlockedIncrement((PLONG
)&SessionGlobal
->ReferenceCount
);
1666 InterlockedIncrement(&SessionGlobal
->ResidentProcessCount
);
1667 InterlockedIncrement(&SessionGlobal
->ProcessReferenceToSession
);
1669 /* Set the session pointer */
1670 ASSERT(NewProcess
->Session
== NULL
);
1671 NewProcess
->Session
= SessionGlobal
;
1673 /* Insert it into the process list */
1674 InsertTailList(&SessionGlobal
->ProcessList
, &NewProcess
->SessionProcessLinks
);
1677 PspSetProcessFlag(NewProcess
, PSF_PROCESS_IN_SESSION_BIT
);
1682 MiSessionInitializeWorkingSetList(VOID
)
1685 PMMPTE PointerPte
, PointerPde
;
1688 PFN_NUMBER PageFrameIndex
;
1689 PMM_SESSION_SPACE SessionGlobal
;
1690 BOOLEAN AllocatedPageTable
;
1691 PMMWSL WorkingSetList
;
1693 /* Get pointers to session global and the session working set list */
1694 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
1695 WorkingSetList
= (PMMWSL
)MiSessionSpaceWs
;
1697 /* Fill out the two pointers */
1698 MmSessionSpace
->Vm
.VmWorkingSetList
= WorkingSetList
;
1699 MmSessionSpace
->Wsle
= (PMMWSLE
)WorkingSetList
->UsedPageTableEntries
;
1701 /* Get the PDE for the working set, and check if it's already allocated */
1702 PointerPde
= MiAddressToPde(WorkingSetList
);
1703 if (PointerPde
->u
.Hard
.Valid
== 1)
1705 /* Nope, we'll have to do it */
1706 ASSERT(PointerPde
->u
.Hard
.Global
== 0);
1707 AllocatedPageTable
= FALSE
;
1711 /* Yep, that makes our job easier */
1712 AllocatedPageTable
= TRUE
;
1715 /* Get the PTE for the working set */
1716 PointerPte
= MiAddressToPte(WorkingSetList
);
1718 /* Initialize the working set lock, and lock the PFN database */
1719 ExInitializePushLock(&SessionGlobal
->Vm
.WorkingSetMutex
);
1720 //MmLockPageableSectionByHandle(ExPageLockHandle);
1721 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1723 /* Check if we need a page table */
1724 if (AllocatedPageTable
== TRUE
)
1726 /* Get a zeroed colored zero page */
1727 Color
= MI_GET_NEXT_COLOR();
1728 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
1729 if (!PageFrameIndex
)
1731 /* No zero pages, grab a free one */
1732 PageFrameIndex
= MiRemoveAnyPage(Color
);
1734 /* Zero it outside the PFN lock */
1735 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1736 MiZeroPhysicalPage(PageFrameIndex
);
1737 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1740 /* Write a valid PDE for it */
1741 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
1742 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
1743 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1745 /* Add this into the list */
1746 Index
= ((ULONG_PTR
)WorkingSetList
- (ULONG_PTR
)MmSessionBase
) >> 22;
1747 MmSessionSpace
->PageTables
[Index
] = TempPte
;
1749 /* Initialize the page directory page, and now zero the working set list itself */
1750 MiInitializePfnForOtherProcess(PageFrameIndex
,
1752 MmSessionSpace
->SessionPageDirectoryIndex
);
1753 KeZeroPages(PointerPte
, PAGE_SIZE
);
1756 /* Get a zeroed colored zero page */
1757 Color
= MI_GET_NEXT_COLOR();
1758 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
1759 if (!PageFrameIndex
)
1761 /* No zero pages, grab a free one */
1762 PageFrameIndex
= MiRemoveAnyPage(Color
);
1764 /* Zero it outside the PFN lock */
1765 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1766 MiZeroPhysicalPage(PageFrameIndex
);
1767 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1770 /* Write a valid PTE for it */
1771 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
1772 TempPte
.u
.Hard
.Dirty
= TRUE
;
1773 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
1775 /* Initialize the working set list page */
1776 MiInitializePfnAndMakePteValid(PageFrameIndex
, PointerPte
, TempPte
);
1778 /* Now we can release the PFN database lock */
1779 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1781 /* Fill out the working set structure */
1782 MmSessionSpace
->Vm
.Flags
.SessionSpace
= 1;
1783 MmSessionSpace
->Vm
.MinimumWorkingSetSize
= 20;
1784 MmSessionSpace
->Vm
.MaximumWorkingSetSize
= 384;
1785 WorkingSetList
->LastEntry
= 20;
1786 WorkingSetList
->HashTable
= NULL
;
1787 WorkingSetList
->HashTableSize
= 0;
1788 WorkingSetList
->Wsle
= MmSessionSpace
->Wsle
;
1790 /* FIXME: Handle list insertions */
1791 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
1792 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
1793 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Flink
== NULL
);
1794 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Blink
== NULL
);
1796 /* All done, return */
1797 //MmUnlockPageableImageSection(ExPageLockHandle);
1798 return STATUS_SUCCESS
;
1803 MiSessionCreateInternal(OUT PULONG SessionId
)
1805 PEPROCESS Process
= PsGetCurrentProcess();
1806 ULONG NewFlags
, Flags
, Size
, i
, Color
;
1808 PMMPTE PointerPte
, PageTables
, SessionPte
;
1810 PMM_SESSION_SPACE SessionGlobal
;
1814 PFN_NUMBER SessionPageDirIndex
;
1815 PFN_NUMBER TagPage
[MI_SESSION_TAG_PAGES_MAXIMUM
];
1816 PFN_NUMBER DataPage
[MI_SESSION_DATA_PAGES_MAXIMUM
];
1818 /* This should not exist yet */
1819 ASSERT(MmIsAddressValid(MmSessionSpace
) == FALSE
);
1821 /* Loop so we can set the session-is-creating flag */
1822 Flags
= Process
->Flags
;
1825 /* Check if it's already set */
1826 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
1829 DPRINT1("Lost session race\n");
1830 return STATUS_ALREADY_COMMITTED
;
1833 /* Now try to set it */
1834 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
1835 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
1837 if (NewFlags
== Flags
) break;
1839 /* It changed, try again */
1843 /* Now we should own the flag */
1844 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1847 * Session space covers everything from 0xA0000000 to 0xC0000000.
1848 * Allocate enough page tables to describe the entire region
1850 Size
= (0x20000000 / PDE_MAPPED_VA
) * sizeof(MMPTE
);
1851 PageTables
= ExAllocatePoolWithTag(NonPagedPool
, Size
, 'tHmM');
1852 ASSERT(PageTables
!= NULL
);
1853 RtlZeroMemory(PageTables
, Size
);
1855 /* Lock the session ID creation mutex */
1856 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1858 /* Allocate a new Session ID */
1859 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
1860 if (*SessionId
== 0xFFFFFFFF)
1862 /* We ran out of session IDs, we should expand */
1863 DPRINT1("Too many sessions created. Expansion not yet supported\n");
1864 ExFreePoolWithTag(PageTables
, 'tHmM');
1865 return STATUS_NO_MEMORY
;
1868 /* Unlock the session ID creation mutex */
1869 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1871 /* Reserve the global PTEs */
1872 SessionPte
= MiReserveSystemPtes(MiSessionDataPages
, SystemPteSpace
);
1873 ASSERT(SessionPte
!= NULL
);
1875 /* Acquire the PFN lock while we set everything up */
1876 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1878 /* Loop the global PTEs */
1879 TempPte
.u
.Long
= ValidKernelPte
.u
.Long
;
1880 for (i
= 0; i
< MiSessionDataPages
; i
++)
1882 /* Get a zeroed colored zero page */
1883 Color
= MI_GET_NEXT_COLOR();
1884 DataPage
[i
] = MiRemoveZeroPageSafe(Color
);
1887 /* No zero pages, grab a free one */
1888 DataPage
[i
] = MiRemoveAnyPage(Color
);
1890 /* Zero it outside the PFN lock */
1891 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1892 MiZeroPhysicalPage(DataPage
[i
]);
1893 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1896 /* Fill the PTE out */
1897 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1898 MI_WRITE_VALID_PTE(SessionPte
+ i
, TempPte
);
1901 /* Set the pointer to global space */
1902 SessionGlobal
= MiPteToAddress(SessionPte
);
1904 /* Get a zeroed colored zero page */
1905 Color
= MI_GET_NEXT_COLOR();
1906 SessionPageDirIndex
= MiRemoveZeroPageSafe(Color
);
1907 if (!SessionPageDirIndex
)
1909 /* No zero pages, grab a free one */
1910 SessionPageDirIndex
= MiRemoveAnyPage(Color
);
1912 /* Zero it outside the PFN lock */
1913 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1914 MiZeroPhysicalPage(SessionPageDirIndex
);
1915 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1918 /* Fill the PTE out */
1919 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
1920 TempPte
.u
.Hard
.PageFrameNumber
= SessionPageDirIndex
;
1922 /* Setup, allocate, fill out the MmSessionSpace PTE */
1923 PointerPde
= MiAddressToPde(MmSessionSpace
);
1924 ASSERT(PointerPde
->u
.Long
== 0);
1925 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1926 MiInitializePfnForOtherProcess(SessionPageDirIndex
,
1928 SessionPageDirIndex
);
1929 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex
)->u1
.WsIndex
== 0);
1931 /* Loop all the local PTEs for it */
1932 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
1933 PointerPte
= MiAddressToPte(MmSessionSpace
);
1934 for (i
= 0; i
< MiSessionDataPages
; i
++)
1936 /* And fill them out */
1937 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
1938 MiInitializePfnAndMakePteValid(DataPage
[i
], PointerPte
+ i
, TempPte
);
1939 ASSERT(MI_PFN_ELEMENT(DataPage
[i
])->u1
.WsIndex
== 0);
1942 /* Finally loop all of the session pool tag pages */
1943 for (i
= 0; i
< MiSessionTagPages
; i
++)
1945 /* Grab a zeroed colored page */
1946 Color
= MI_GET_NEXT_COLOR();
1947 TagPage
[i
] = MiRemoveZeroPageSafe(Color
);
1950 /* No zero pages, grab a free one */
1951 TagPage
[i
] = MiRemoveAnyPage(Color
);
1953 /* Zero it outside the PFN lock */
1954 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1955 MiZeroPhysicalPage(TagPage
[i
]);
1956 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1959 /* Fill the PTE out */
1960 TempPte
.u
.Hard
.PageFrameNumber
= TagPage
[i
];
1961 MiInitializePfnAndMakePteValid(TagPage
[i
],
1962 PointerPte
+ MiSessionDataPages
+ i
,
1966 /* PTEs have been setup, release the PFN lock */
1967 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1969 /* Fill out the session space structure now */
1970 MmSessionSpace
->GlobalVirtualAddress
= SessionGlobal
;
1971 MmSessionSpace
->ReferenceCount
= 1;
1972 MmSessionSpace
->ResidentProcessCount
= 1;
1973 MmSessionSpace
->u
.LongFlags
= 0;
1974 MmSessionSpace
->SessionId
= *SessionId
;
1975 MmSessionSpace
->LocaleId
= PsDefaultSystemLocaleId
;
1976 MmSessionSpace
->SessionPageDirectoryIndex
= SessionPageDirIndex
;
1977 MmSessionSpace
->Color
= Color
;
1978 MmSessionSpace
->NonPageablePages
= MiSessionCreateCharge
;
1979 MmSessionSpace
->CommittedPages
= MiSessionCreateCharge
;
1980 MmSessionSpace
->PageTables
= PageTables
;
1981 MmSessionSpace
->PageTables
[PointerPde
- MiAddressToPde(MmSessionBase
)] = *PointerPde
;
1982 InitializeListHead(&MmSessionSpace
->ImageList
);
1983 DPRINT1("Session %d is ready to go: 0x%p 0x%p, %lx 0x%p\n",
1984 *SessionId
, MmSessionSpace
, SessionGlobal
, SessionPageDirIndex
, PageTables
);
1986 /* Initialize session pool */
1987 //Status = MiInitializeSessionPool();
1988 Status
= STATUS_SUCCESS
;
1989 ASSERT(NT_SUCCESS(Status
) == TRUE
);
1991 /* Initialize system space */
1992 Result
= MiInitializeSystemSpaceMap(&SessionGlobal
->Session
);
1993 ASSERT(Result
== TRUE
);
1995 /* Initialize the process list, make sure the workign set list is empty */
1996 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
1997 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
1998 InitializeListHead(&SessionGlobal
->ProcessList
);
2000 /* We're done, clear the flag */
2001 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
2002 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
2004 /* Insert the process into the session */
2005 ASSERT(Process
->Session
== NULL
);
2006 ASSERT(SessionGlobal
->ProcessReferenceToSession
== 0);
2007 SessionGlobal
->ProcessReferenceToSession
= 1;
2010 InterlockedIncrement(&MmSessionDataPages
);
2011 return STATUS_SUCCESS
;
2016 MmSessionCreate(OUT PULONG SessionId
)
2018 PEPROCESS Process
= PsGetCurrentProcess();
2019 ULONG SessionLeaderExists
;
2022 /* Fail if the process is already in a session */
2023 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
2025 DPRINT1("Process already in session\n");
2026 return STATUS_ALREADY_COMMITTED
;
2029 /* Check if the process is already the session leader */
2030 if (!Process
->Vm
.Flags
.SessionLeader
)
2032 /* Atomically set it as the leader */
2033 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
2034 if (SessionLeaderExists
)
2036 DPRINT1("Session leader race\n");
2037 return STATUS_INVALID_SYSTEM_SERVICE
;
2040 /* Do the work required to upgrade him */
2041 MiSessionLeader(Process
);
2044 /* Create the session */
2045 KeEnterCriticalRegion();
2046 Status
= MiSessionCreateInternal(SessionId
);
2047 if (!NT_SUCCESS(Status
))
2049 KeLeaveCriticalRegion();
2053 /* Set up the session working set */
2054 Status
= MiSessionInitializeWorkingSetList();
2055 if (!NT_SUCCESS(Status
))
2058 //MiDereferenceSession();
2060 KeLeaveCriticalRegion();
2065 KeLeaveCriticalRegion();
2067 /* Set and assert the flags, and return */
2068 MmSessionSpace
->u
.Flags
.Initialized
= 1;
2069 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
2070 ASSERT(MiSessionLeaderExists
== 1);
2076 MmSessionDelete(IN ULONG SessionId
)
2078 PEPROCESS Process
= PsGetCurrentProcess();
2080 /* Process must be in a session */
2081 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
2083 DPRINT1("Not in a session!\n");
2084 return STATUS_UNABLE_TO_FREE_VM
;
2087 /* It must be the session leader */
2088 if (!Process
->Vm
.Flags
.SessionLeader
)
2090 DPRINT1("Not a session leader!\n");
2091 return STATUS_UNABLE_TO_FREE_VM
;
2094 /* Remove one reference count */
2095 KeEnterCriticalRegion();
2097 KeLeaveCriticalRegion();
2100 return STATUS_SUCCESS
;
2103 /* SYSTEM CALLS ***************************************************************/
2107 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
2108 IN OUT PULONG_PTR NumberOfPages
,
2109 IN OUT PULONG_PTR UserPfnArray
)
2112 return STATUS_NOT_IMPLEMENTED
;
2117 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
2118 IN ULONG_PTR NumberOfPages
,
2119 IN OUT PULONG_PTR UserPfnArray
)
2122 return STATUS_NOT_IMPLEMENTED
;
2127 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
2128 IN ULONG_PTR NumberOfPages
,
2129 IN OUT PULONG_PTR UserPfnArray
)
2132 return STATUS_NOT_IMPLEMENTED
;
2137 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
2138 IN OUT PULONG_PTR NumberOfPages
,
2139 IN OUT PULONG_PTR UserPfnArray
)
2142 return STATUS_NOT_IMPLEMENTED
;