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
;
23 /* PRIVATE FUNCTIONS **********************************************************/
27 MiRosTakeOverSharedUserPage(IN PEPROCESS Process
)
30 PMEMORY_AREA MemoryArea
;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
32 PVOID AllocatedBase
= (PVOID
)MM_SHARED_USER_DATA_VA
;
33 BoundaryAddressMultiple
.QuadPart
= 0;
35 Status
= MmCreateMemoryArea(&Process
->Vm
,
36 MEMORY_AREA_OWNED_BY_ARM3
,
43 BoundaryAddressMultiple
);
44 ASSERT(NT_SUCCESS(Status
));
49 MiCreatePebOrTeb(IN PEPROCESS Process
,
53 PETHREAD Thread
= PsGetCurrentThread();
57 ULONG_PTR StartAddress
, EndAddress
;
58 LARGE_INTEGER CurrentTime
;
59 TABLE_SEARCH_RESULT Result
= TableFoundNode
;
60 PMMADDRESS_NODE Parent
;
63 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD_LONG
), 'ldaV');
64 if (!Vad
) return STATUS_NO_MEMORY
;
66 /* Setup the primary flags with the size, and make it commited, private, RW */
68 Vad
->u
.VadFlags
.CommitCharge
= BYTES_TO_PAGES(Size
);
69 Vad
->u
.VadFlags
.MemCommit
= TRUE
;
70 Vad
->u
.VadFlags
.PrivateMemory
= TRUE
;
71 Vad
->u
.VadFlags
.Protection
= MM_READWRITE
;
72 Vad
->u
.VadFlags
.NoChange
= TRUE
;
74 /* Setup the secondary flags to make it a secured, writable, long VAD */
75 Vad
->u2
.LongFlags2
= 0;
76 Vad
->u2
.VadFlags2
.OneSecured
= TRUE
;
77 Vad
->u2
.VadFlags2
.LongVad
= TRUE
;
78 Vad
->u2
.VadFlags2
.ReadOnly
= FALSE
;
80 /* Lock the process address space */
81 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
83 /* Check if this is a PEB creation */
84 if (Size
== sizeof(PEB
))
86 /* Start at the highest valid address */
87 StartAddress
= (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1;
89 /* Select the random coefficient */
90 KeQueryTickCount(&CurrentTime
);
91 CurrentTime
.LowPart
&= ((64 * _1KB
) >> PAGE_SHIFT
) - 1;
92 if (CurrentTime
.LowPart
<= 1) CurrentTime
.LowPart
= 2;
93 RandomCoeff
= CurrentTime
.LowPart
<< PAGE_SHIFT
;
95 /* Select the highest valid address minus the random coefficient */
96 StartAddress
-= RandomCoeff
;
97 EndAddress
= StartAddress
+ ROUND_TO_PAGES(Size
) - 1;
99 /* Try to find something below the random upper margin */
100 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
108 /* Check for success. TableFoundNode means nothing free. */
109 if (Result
== TableFoundNode
)
111 /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
112 Result
= MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size
),
113 (ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1,
118 /* Bail out, if still nothing free was found */
119 if (Result
== TableFoundNode
) return STATUS_NO_MEMORY
;
122 /* Validate that it came from the VAD ranges */
123 ASSERT(*Base
>= (ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
);
125 /* Build the rest of the VAD now */
126 Vad
->StartingVpn
= (*Base
) >> PAGE_SHIFT
;
127 Vad
->EndingVpn
= ((*Base
) + Size
- 1) >> PAGE_SHIFT
;
128 Vad
->u3
.Secured
.StartVpn
= *Base
;
129 Vad
->u3
.Secured
.EndVpn
= (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1);
130 Vad
->u1
.Parent
= NULL
;
132 /* FIXME: Should setup VAD bitmap */
133 Status
= STATUS_SUCCESS
;
135 /* Pretend as if we own the working set */
136 MiLockProcessWorkingSet(Process
, Thread
);
139 ASSERT(Vad
->EndingVpn
>= Vad
->StartingVpn
);
140 Process
->VadRoot
.NodeHint
= Vad
;
141 Vad
->ControlArea
= NULL
; // For Memory-Area hack
142 Vad
->FirstPrototypePte
= NULL
;
143 DPRINT("VAD: %p\n", Vad
);
144 DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base
, Process
->ImageFileName
);
145 MiInsertNode(&Process
->VadRoot
, (PVOID
)Vad
, Parent
, Result
);
147 /* Release the working set */
148 MiUnlockProcessWorkingSet(Process
, Thread
);
150 /* Release the address space lock */
151 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
153 /* Return the status */
159 MmDeleteTeb(IN PEPROCESS Process
,
163 PETHREAD Thread
= PsGetCurrentThread();
165 PMM_AVL_TABLE VadTree
= &Process
->VadRoot
;
166 DPRINT("Deleting TEB: %p in %16s\n", Teb
, Process
->ImageFileName
);
168 /* TEB is one page */
169 TebEnd
= (ULONG_PTR
)Teb
+ ROUND_TO_PAGES(sizeof(TEB
)) - 1;
171 /* Attach to the process */
172 KeAttachProcess(&Process
->Pcb
);
174 /* Lock the process address space */
175 KeAcquireGuardedMutex(&Process
->AddressCreationLock
);
177 /* Find the VAD, make sure it's a TEB VAD */
178 Vad
= MiLocateAddress(Teb
);
179 DPRINT("Removing node for VAD: %lx %lx\n", Vad
->StartingVpn
, Vad
->EndingVpn
);
181 if (Vad
->StartingVpn
!= ((ULONG_PTR
)Teb
>> PAGE_SHIFT
))
183 /* Bug in the AVL code? */
184 DPRINT1("Corrupted VAD!\n");
188 /* Sanity checks for a valid TEB VAD */
189 ASSERT((Vad
->StartingVpn
== ((ULONG_PTR
)Teb
>> PAGE_SHIFT
) &&
190 (Vad
->EndingVpn
== (TebEnd
>> PAGE_SHIFT
))));
191 ASSERT(Vad
->u
.VadFlags
.NoChange
== TRUE
);
192 ASSERT(Vad
->u2
.VadFlags2
.OneSecured
== TRUE
);
193 ASSERT(Vad
->u2
.VadFlags2
.MultipleSecured
== FALSE
);
195 /* Lock the working set */
196 MiLockProcessWorkingSet(Process
, Thread
);
198 /* Remove this VAD from the tree */
199 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
200 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
202 /* Delete the pages */
203 MiDeleteVirtualAddresses((ULONG_PTR
)Teb
, TebEnd
, NULL
);
205 /* Release the working set */
206 MiUnlockProcessWorkingSet(Process
, Thread
);
212 /* Release the address space lock */
213 KeReleaseGuardedMutex(&Process
->AddressCreationLock
);
221 MmDeleteKernelStack(IN PVOID StackBase
,
225 PFN_NUMBER PageFrameNumber
, PageTableFrameNumber
;
226 PFN_COUNT StackPages
;
227 PMMPFN Pfn1
;//, Pfn2;
232 // This should be the guard page, so decrement by one
234 PointerPte
= MiAddressToPte(StackBase
);
238 // Calculate pages used
240 StackPages
= BYTES_TO_PAGES(GuiStack
?
241 KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
);
243 /* Acquire the PFN lock */
244 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
249 for (i
= 0; i
< StackPages
; i
++)
252 // Check if this is a valid PTE
254 if (PointerPte
->u
.Hard
.Valid
== 1)
256 /* Get the PTE's page */
257 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
258 Pfn1
= MiGetPfnEntry(PageFrameNumber
);
259 #if 1 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
260 /* Now get the page of the page table mapping it */
261 PageTableFrameNumber
= Pfn1
->u4
.PteFrame
;
262 //Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
264 /* Remove a shared reference, since the page is going away */
265 DPRINT("SystemPTE PDE: %lx\n", PageTableFrameNumber
);
266 //MiDecrementShareCount(Pfn2, PageTableFrameNumber);
268 /* Set the special pending delete marker */
269 MI_SET_PFN_DELETED(Pfn1
);
271 /* And now delete the actual stack page */
272 MiDecrementShareCount(Pfn1
, PageFrameNumber
);
282 // We should be at the guard page now
284 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
286 /* Release the PFN lock */
287 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
292 MiReleaseSystemPtes(PointerPte
, StackPages
+ 1, SystemPteSpace
);
297 MmCreateKernelStack(IN BOOLEAN GuiStack
,
300 PFN_COUNT StackPtes
, StackPages
;
301 PMMPTE PointerPte
, StackPte
;
303 MMPTE TempPte
, InvalidPte
;
305 PFN_NUMBER PageFrameIndex
;
309 // Calculate pages needed
314 // We'll allocate 64KB stack, but only commit 12K
316 StackPtes
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
);
317 StackPages
= BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT
);
323 // We'll allocate 12K and that's it
325 StackPtes
= BYTES_TO_PAGES(KERNEL_STACK_SIZE
);
326 StackPages
= StackPtes
;
330 // Reserve stack pages, plus a guard page
332 StackPte
= MiReserveSystemPtes(StackPtes
+ 1, SystemPteSpace
);
333 if (!StackPte
) return NULL
;
336 // Get the stack address
338 BaseAddress
= MiPteToAddress(StackPte
+ StackPtes
+ 1);
341 // Select the right PTE address where we actually start committing pages
343 PointerPte
= StackPte
;
344 if (GuiStack
) PointerPte
+= BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE
-
345 KERNEL_LARGE_STACK_COMMIT
);
348 /* Setup the temporary invalid PTE */
349 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
351 /* Setup the template stack PTE */
352 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
+ 1, MM_READWRITE
, 0);
355 // Acquire the PFN DB lock
357 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
360 // Loop each stack page
362 for (i
= 0; i
< StackPages
; i
++)
369 /* Get a page and write the current invalid PTE */
370 MI_SET_USAGE(MI_USAGE_KERNEL_STACK
);
371 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
372 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
373 MI_WRITE_INVALID_PTE(PointerPte
, InvalidPte
);
375 /* Initialize the PFN entry for this page */
376 MiInitializePfn(PageFrameIndex
, PointerPte
, 1);
378 /* Write the valid PTE */
379 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
380 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
384 // Release the PFN lock
386 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
389 // Return the stack address
396 MmGrowKernelStackEx(IN PVOID StackPointer
,
399 PKTHREAD Thread
= KeGetCurrentThread();
400 PMMPTE LimitPte
, NewLimitPte
, LastPte
;
402 MMPTE TempPte
, InvalidPte
;
403 PFN_NUMBER PageFrameIndex
;
406 // Make sure the stack did not overflow
408 ASSERT(((ULONG_PTR
)Thread
->StackBase
- (ULONG_PTR
)Thread
->StackLimit
) <=
409 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
412 // Get the current stack limit
414 LimitPte
= MiAddressToPte(Thread
->StackLimit
);
415 ASSERT(LimitPte
->u
.Hard
.Valid
== 1);
418 // Get the new one and make sure this isn't a retarded request
420 NewLimitPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)StackPointer
- GrowSize
));
421 if (NewLimitPte
== LimitPte
) return STATUS_SUCCESS
;
424 // Now make sure you're not going past the reserved space
426 LastPte
= MiAddressToPte((PVOID
)((ULONG_PTR
)Thread
->StackBase
-
427 KERNEL_LARGE_STACK_SIZE
));
428 if (NewLimitPte
< LastPte
)
433 DPRINT1("Thread wants too much stack\n");
434 return STATUS_STACK_OVERFLOW
;
438 // Calculate the number of new pages
442 /* Setup the temporary invalid PTE */
443 MI_MAKE_SOFTWARE_PTE(&InvalidPte
, MM_NOACCESS
);
446 // Acquire the PFN DB lock
448 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
451 // Loop each stack page
453 while (LimitPte
>= NewLimitPte
)
455 /* Get a page and write the current invalid PTE */
456 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION
);
457 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName
);
458 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
459 MI_WRITE_INVALID_PTE(LimitPte
, InvalidPte
);
461 /* Initialize the PFN entry for this page */
462 MiInitializePfn(PageFrameIndex
, LimitPte
, 1);
464 /* Setup the template stack PTE */
465 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, LimitPte
, MM_READWRITE
, PageFrameIndex
);
467 /* Write the valid PTE */
468 MI_WRITE_VALID_PTE(LimitPte
--, TempPte
);
472 // Release the PFN lock
474 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
479 Thread
->StackLimit
= (ULONG_PTR
)MiPteToAddress(NewLimitPte
);
480 return STATUS_SUCCESS
;
485 MmGrowKernelStack(IN PVOID StackPointer
)
488 // Call the extended version
490 return MmGrowKernelStackEx(StackPointer
, KERNEL_LARGE_STACK_COMMIT
);
495 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
496 IN UCHAR MemoryPriority
)
501 // Check if we have less then 16MB of Physical Memory
503 if ((MmSystemSize
== MmSmallSystem
) &&
504 (MmNumberOfPhysicalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
507 // Always use background priority
509 MemoryPriority
= MEMORY_PRIORITY_BACKGROUND
;
513 // Save the old priority and update it
515 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
516 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
519 // Return the old priority
526 MmGetSessionLocaleId(VOID
)
532 // Get the current process
534 Process
= PsGetCurrentProcess();
537 // Check if it's the Session Leader
539 if (Process
->Vm
.Flags
.SessionLeader
)
542 // Make sure it has a valid Session
544 if (Process
->Session
)
550 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
556 // Not a session leader, return the default
558 return PsDefaultThreadLocaleId
;
563 MmCreatePeb(IN PEPROCESS Process
,
564 IN PINITIAL_PEB InitialPeb
,
568 LARGE_INTEGER SectionOffset
;
570 PVOID TableBase
= NULL
;
571 PIMAGE_NT_HEADERS NtHeaders
;
572 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
574 USHORT Characteristics
;
575 KAFFINITY ProcessAffinityMask
= 0;
576 SectionOffset
.QuadPart
= (ULONGLONG
)0;
582 KeAttachProcess(&Process
->Pcb
);
587 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
597 DPRINT("NLS Tables at: %p\n", TableBase
);
598 if (!NT_SUCCESS(Status
))
600 /* Cleanup and exit */
608 Status
= MiCreatePebOrTeb(Process
, sizeof(PEB
), (PULONG_PTR
)&Peb
);
609 DPRINT("PEB at: %p\n", Peb
);
610 if (!NT_SUCCESS(Status
))
612 /* Cleanup and exit */
618 // Use SEH in case we can't load the PEB
623 // Initialize the PEB
625 RtlZeroMemory(Peb
, sizeof(PEB
));
630 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
631 Peb
->InheritedAddressSpace
= InitialPeb
->InheritedAddressSpace
;
632 Peb
->Mutant
= InitialPeb
->Mutant
;
633 Peb
->ImageUsesLargePages
= InitialPeb
->ImageUsesLargePages
;
638 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
639 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
640 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
643 // Default Version Data (could get changed below)
645 Peb
->OSMajorVersion
= NtMajorVersion
;
646 Peb
->OSMinorVersion
= NtMinorVersion
;
647 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
648 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
649 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
652 // Heap and Debug Data
654 Peb
->NumberOfProcessors
= KeNumberProcessors
;
655 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
);
656 Peb
->NtGlobalFlag
= NtGlobalFlag
;
657 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
658 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
659 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
660 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
661 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
662 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
664 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
665 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
670 if (Process
->Session
) Peb
->SessionId
= 0; // MmGetSessionId(Process);
672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
678 _SEH2_YIELD(return _SEH2_GetExceptionCode());
683 // Use SEH in case we can't load the image
690 NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
);
691 Characteristics
= NtHeaders
->FileHeader
.Characteristics
;
693 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
699 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
709 // Use SEH in case we can't load the headers
714 // Get the Image Config Data too
716 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
718 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
725 ProbeForRead(ImageConfigData
,
726 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
731 // Write subsystem data
733 Peb
->ImageSubsystem
= NtHeaders
->OptionalHeader
.Subsystem
;
734 Peb
->ImageSubsystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
735 Peb
->ImageSubsystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
738 // Check for version data
740 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
743 // Extract values and write them
745 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
746 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
747 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
748 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
750 /* Process CSD version override */
751 if ((ImageConfigData
) && (ImageConfigData
->CSDVersion
))
753 /* Take the value from the image configuration directory */
754 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
758 /* Process optional process affinity mask override */
759 if ((ImageConfigData
) && (ImageConfigData
->ProcessAffinityMask
))
761 /* Take the value from the image configuration directory */
762 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
766 // Check if this is a UP image
767 if (Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
770 // Force it to use CPU 0
772 /* FIXME: this should use the MmRotatingUniprocessorNumber */
773 Peb
->ImageProcessAffinityMask
= 0;
778 // Whatever was configured
780 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
789 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT
);
795 // Detach from the Process
799 return STATUS_SUCCESS
;
804 MmCreateTeb(IN PEPROCESS Process
,
805 IN PCLIENT_ID ClientId
,
806 IN PINITIAL_TEB InitialTeb
,
810 NTSTATUS Status
= STATUS_SUCCESS
;
816 KeAttachProcess(&Process
->Pcb
);
821 Status
= MiCreatePebOrTeb(Process
, sizeof(TEB
), (PULONG_PTR
)&Teb
);
822 ASSERT(NT_SUCCESS(Status
));
825 // Use SEH in case we can't load the TEB
830 // Initialize the PEB
832 RtlZeroMemory(Teb
, sizeof(TEB
));
838 Teb
->NtTib
.ExceptionList
= NULL
;
840 Teb
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
842 Teb
->NtTib
.Self
= (PNT_TIB
)Teb
;
845 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
847 Teb
->NtTib
.Version
= 30 << 8;
852 Teb
->ClientId
= *ClientId
;
853 Teb
->RealClientId
= *ClientId
;
854 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
855 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
858 // Check if we have a grandparent TEB
860 if ((InitialTeb
->PreviousStackBase
== NULL
) &&
861 (InitialTeb
->PreviousStackLimit
== NULL
))
864 // Use initial TEB values
866 Teb
->NtTib
.StackBase
= InitialTeb
->StackBase
;
867 Teb
->NtTib
.StackLimit
= InitialTeb
->StackLimit
;
868 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
873 // Use grandparent TEB values
875 Teb
->NtTib
.StackBase
= InitialTeb
->PreviousStackBase
;
876 Teb
->NtTib
.StackLimit
= InitialTeb
->PreviousStackLimit
;
880 // Initialize the static unicode string
882 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
883 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
885 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
890 Status
= _SEH2_GetExceptionCode();
904 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess
)
910 /* Setup some bogus list data */
911 MmWorkingSetList
->LastEntry
= CurrentProcess
->Vm
.MinimumWorkingSetSize
;
912 MmWorkingSetList
->HashTable
= NULL
;
913 MmWorkingSetList
->HashTableSize
= 0;
914 MmWorkingSetList
->NumberOfImageWaiters
= 0;
915 MmWorkingSetList
->Wsle
= (PVOID
)0xDEADBABE;
916 MmWorkingSetList
->VadBitMapHint
= 1;
917 MmWorkingSetList
->HashTableStart
= (PVOID
)0xBADAB00B;
918 MmWorkingSetList
->HighestPermittedHashAddress
= (PVOID
)0xCAFEBABE;
919 MmWorkingSetList
->FirstFree
= 1;
920 MmWorkingSetList
->FirstDynamic
= 2;
921 MmWorkingSetList
->NextSlot
= 3;
922 MmWorkingSetList
->LastInitializedWsle
= 4;
924 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
925 Pfn1
= MiGetPfnEntry(CurrentProcess
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
);
926 ASSERT(Pfn1
->u4
.PteFrame
== MiGetPfnEntryIndex(Pfn1
));
927 Pfn1
->u1
.Event
= (PKEVENT
)CurrentProcess
;
929 /* Map the process working set in kernel space */
930 sysPte
= MiReserveSystemPtes(1, SystemPteSpace
);
931 MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte
, sysPte
, MM_READWRITE
, CurrentProcess
->WorkingSetPage
);
932 MI_WRITE_VALID_PTE(sysPte
, tempPte
);
933 CurrentProcess
->Vm
.VmWorkingSetList
= MiPteToAddress(sysPte
);
938 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
939 IN PEPROCESS ProcessClone OPTIONAL
,
940 IN PVOID Section OPTIONAL
,
942 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
944 NTSTATUS Status
= STATUS_SUCCESS
;
947 PROS_SECTION_OBJECT SectionObject
= Section
;
951 PFN_NUMBER PageFrameNumber
;
952 UNICODE_STRING FileName
;
958 /* We should have a PDE */
959 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] != 0);
960 ASSERT(Process
->PdeUpdateNeeded
== FALSE
);
962 /* Attach to the process */
963 KeAttachProcess(&Process
->Pcb
);
965 /* The address space should now been in phase 1 or 0 */
966 ASSERT(Process
->AddressSpaceInitialized
<= 1);
967 Process
->AddressSpaceInitialized
= 2;
969 /* Initialize the Addresss Space lock */
970 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
971 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
973 /* Initialize AVL tree */
974 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
975 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
977 /* Lock PFN database */
978 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
980 /* Setup the PFN for the PDE base of this process */
982 PointerPte
= MiAddressToPte(PXE_BASE
);
984 PointerPte
= MiAddressToPte(PDE_BASE
);
986 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
987 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == PageFrameNumber
* PAGE_SIZE
);
988 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
990 /* Do the same for hyperspace */
992 PointerPde
= MiAddressToPxe((PVOID
)HYPER_SPACE
);
994 PointerPde
= MiAddressToPde(HYPER_SPACE
);
996 PageFrameNumber
= PFN_FROM_PTE(PointerPde
);
997 //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
998 MiInitializePfn(PageFrameNumber
, (PMMPTE
)PointerPde
, TRUE
);
1000 /* Setup the PFN for the PTE for the working set */
1001 PointerPte
= MiAddressToPte(MI_WORKING_SET_LIST
);
1002 MI_MAKE_HARDWARE_PTE(&TempPte
, PointerPte
, MM_READWRITE
, 0);
1003 ASSERT(PointerPte
->u
.Long
!= 0);
1004 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
1005 MI_WRITE_INVALID_PTE(PointerPte
, DemandZeroPte
);
1006 MiInitializePfn(PageFrameNumber
, PointerPte
, TRUE
);
1007 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameNumber
;
1008 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1010 /* Now initialize the working set list */
1011 MiInitializeWorkingSetList(Process
);
1014 ASSERT(Process
->PhysicalVadRoot
== NULL
);
1016 /* Release PFN lock */
1017 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1019 /* Lock the VAD, ARM3-owned ranges away */
1020 MiRosTakeOverSharedUserPage(Process
);
1022 /* Check if there's a Section Object */
1025 /* Determine the image file name and save it to EPROCESS */
1026 FileName
= SectionObject
->FileObject
->FileName
;
1027 Source
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
1028 if (FileName
.Buffer
)
1030 /* Loop the file name*/
1031 while (Source
> FileName
.Buffer
)
1033 /* Make sure this isn't a backslash */
1034 if (*--Source
== OBJ_NAME_PATH_SEPARATOR
)
1036 /* If so, stop it here */
1042 /* Otherwise, keep going */
1048 /* Copy the to the process and truncate it to 15 characters if necessary */
1049 Destination
= Process
->ImageFileName
;
1050 Length
= min(Length
, sizeof(Process
->ImageFileName
) - 1);
1051 while (Length
--) *Destination
++ = (UCHAR
)*Source
++;
1052 *Destination
= ANSI_NULL
;
1054 /* Check if caller wants an audit name */
1057 /* Setup the audit name */
1058 Status
= SeInitializeProcessAuditName(SectionObject
->FileObject
,
1061 if (!NT_SUCCESS(Status
))
1069 /* Map the section */
1070 Status
= MmMapViewOfSection(Section
,
1081 /* Save the pointer */
1082 Process
->SectionBaseAddress
= ImageBase
;
1085 /* Be nice and detach */
1088 /* Return status to caller */
1095 MmInitializeHandBuiltProcess(IN PEPROCESS Process
,
1096 IN PULONG_PTR DirectoryTableBase
)
1098 /* Share the directory base with the idle process */
1099 DirectoryTableBase
[0] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0];
1100 DirectoryTableBase
[1] = PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[1];
1102 /* Initialize the Addresss Space */
1103 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
1104 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1105 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
1106 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
1107 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
1110 Process
->HasAddressSpace
= TRUE
;//??
1111 return STATUS_SUCCESS
;
1117 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
1119 /* Lock the VAD, ARM3-owned ranges away */
1120 MiRosTakeOverSharedUserPage(Process
);
1121 return STATUS_SUCCESS
;
1125 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1128 MmCreateProcessAddressSpace(IN ULONG MinWs
,
1129 IN PEPROCESS Process
,
1130 OUT PULONG_PTR DirectoryTableBase
)
1133 PFN_NUMBER PdeIndex
, HyperIndex
, WsListIndex
;
1135 MMPTE TempPte
, PdePte
;
1137 PMMPTE SystemTable
, HyperTable
;
1141 /* Choose a process color */
1142 Process
->NextPageColor
= (USHORT
)RtlRandom(&MmProcessColorSeed
);
1144 /* Setup the hyperspace lock */
1145 KeInitializeSpinLock(&Process
->HyperSpaceLock
);
1147 /* Lock PFN database */
1148 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1150 /* Get a zero page for the PDE, if possible */
1151 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1152 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1153 PdeIndex
= MiRemoveZeroPageSafe(Color
);
1156 /* No zero pages, grab a free one */
1157 PdeIndex
= MiRemoveAnyPage(Color
);
1159 /* Zero it outside the PFN lock */
1160 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1161 MiZeroPhysicalPage(PdeIndex
);
1162 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1165 /* Get a zero page for hyperspace, if possible */
1166 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY
);
1167 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1168 HyperIndex
= MiRemoveZeroPageSafe(Color
);
1171 /* No zero pages, grab a free one */
1172 HyperIndex
= MiRemoveAnyPage(Color
);
1174 /* Zero it outside the PFN lock */
1175 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1176 MiZeroPhysicalPage(HyperIndex
);
1177 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1180 /* Get a zero page for the woring set list, if possible */
1181 MI_SET_USAGE(MI_USAGE_PAGE_TABLE
);
1182 Color
= MI_GET_NEXT_PROCESS_COLOR(Process
);
1183 WsListIndex
= MiRemoveZeroPageSafe(Color
);
1186 /* No zero pages, grab a free one */
1187 WsListIndex
= MiRemoveAnyPage(Color
);
1189 /* Zero it outside the PFN lock */
1190 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1191 MiZeroPhysicalPage(WsListIndex
);
1195 /* Release the PFN lock */
1196 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1199 /* Switch to phase 1 initialization */
1200 ASSERT(Process
->AddressSpaceInitialized
== 0);
1201 Process
->AddressSpaceInitialized
= 1;
1203 /* Set the base directory pointers */
1204 Process
->WorkingSetPage
= WsListIndex
;
1205 DirectoryTableBase
[0] = PdeIndex
<< PAGE_SHIFT
;
1206 DirectoryTableBase
[1] = HyperIndex
<< PAGE_SHIFT
;
1208 /* Make sure we don't already have a page directory setup */
1209 ASSERT(Process
->Pcb
.DirectoryTableBase
[0] == 0);
1211 /* Get a PTE to map hyperspace */
1212 PointerPte
= MiReserveSystemPtes(1, SystemPteSpace
);
1213 ASSERT(PointerPte
!= NULL
);
1216 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte
,
1221 /* Set it dirty and map it */
1222 MI_MAKE_DIRTY_PAGE(&PdePte
);
1223 MI_WRITE_VALID_PTE(PointerPte
, PdePte
);
1225 /* Now get hyperspace's page table */
1226 HyperTable
= MiPteToAddress(PointerPte
);
1228 /* Now write the PTE/PDE entry for the working set list index itself */
1229 TempPte
= ValidKernelPte
;
1230 TempPte
.u
.Hard
.PageFrameNumber
= WsListIndex
;
1231 /* Hyperspace is local */
1232 MI_MAKE_LOCAL_PAGE(&TempPte
);
1233 PdeOffset
= MiAddressToPteOffset(MmWorkingSetList
);
1234 HyperTable
[PdeOffset
] = TempPte
;
1236 /* Let go of the system PTE */
1237 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1239 /* Save the PTE address of the page directory itself */
1240 Pfn1
= MiGetPfnEntry(PdeIndex
);
1241 Pfn1
->PteAddress
= (PMMPTE
)PDE_BASE
;
1243 /* Insert us into the Mm process list */
1244 InsertTailList(&MmProcessList
, &Process
->MmProcessLinks
);
1246 /* Get a PTE to map the page directory */
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 the page directory (which we'll double map, so call it a page table */
1261 SystemTable
= MiPteToAddress(PointerPte
);
1263 /* Copy all the kernel mappings */
1264 PdeOffset
= MiGetPdeOffset(MmSystemRangeStart
);
1265 RtlCopyMemory(&SystemTable
[PdeOffset
],
1266 MiAddressToPde(MmSystemRangeStart
),
1267 PAGE_SIZE
- PdeOffset
* sizeof(MMPTE
));
1269 /* Now write the PTE/PDE entry for hyperspace itself */
1270 TempPte
= ValidKernelPte
;
1271 TempPte
.u
.Hard
.PageFrameNumber
= HyperIndex
;
1272 PdeOffset
= MiGetPdeOffset(HYPER_SPACE
);
1273 SystemTable
[PdeOffset
] = TempPte
;
1277 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd
) >= PdeOffset
);
1279 /* Now do the x86 trick of making the PDE a page table itself */
1280 PdeOffset
= MiGetPdeOffset(PTE_BASE
);
1281 TempPte
.u
.Hard
.PageFrameNumber
= PdeIndex
;
1282 SystemTable
[PdeOffset
] = TempPte
;
1284 /* Let go of the system PTE */
1285 MiReleaseSystemPtes(PointerPte
, 1, SystemPteSpace
);
1292 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
1295 PMM_AVL_TABLE VadTree
;
1296 PETHREAD Thread
= PsGetCurrentThread();
1298 /* Only support this */
1299 ASSERT(Process
->AddressSpaceInitialized
== 2);
1301 /* Lock the process address space from changes */
1302 MmLockAddressSpace(&Process
->Vm
);
1304 /* VM is deleted now */
1305 Process
->VmDeleted
= TRUE
;
1307 /* Enumerate the VADs */
1308 VadTree
= &Process
->VadRoot
;
1309 while (VadTree
->NumberGenericTableElements
)
1311 /* Grab the current VAD */
1312 Vad
= (PMMVAD
)VadTree
->BalancedRoot
.RightChild
;
1314 /* Lock the working set */
1315 MiLockProcessWorkingSet(Process
, Thread
);
1317 /* Remove this VAD from the tree */
1318 ASSERT(VadTree
->NumberGenericTableElements
>= 1);
1319 MiRemoveNode((PMMADDRESS_NODE
)Vad
, VadTree
);
1321 /* Only regular VADs supported for now */
1322 ASSERT(Vad
->u
.VadFlags
.VadType
== VadNone
);
1324 /* Check if this is a section VAD */
1325 if (!(Vad
->u
.VadFlags
.PrivateMemory
) && (Vad
->ControlArea
))
1327 /* Remove the view */
1328 MiRemoveMappedView(Process
, Vad
);
1332 /* Delete the addresses */
1333 MiDeleteVirtualAddresses(Vad
->StartingVpn
<< PAGE_SHIFT
,
1334 (Vad
->EndingVpn
<< PAGE_SHIFT
) | (PAGE_SIZE
- 1),
1337 /* Release the working set */
1338 MiUnlockProcessWorkingSet(Process
, Thread
);
1341 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1342 if (Vad
->u
.VadFlags
.Spare
== 1)
1344 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1345 Vad
->u
.VadFlags
.Spare
= 2;
1349 /* Free the VAD memory */
1353 /* Release the address space */
1354 MmUnlockAddressSpace(&Process
->Vm
);
1359 MmDeleteProcessAddressSpace2(IN PEPROCESS Process
)
1363 PFN_NUMBER PageFrameIndex
;
1365 //ASSERT(Process->CommitCharge == 0);
1367 /* Delete the shared user data section (Should be done in clean, not delete) */
1368 ASSERT(MmHighestUserAddress
> (PVOID
)USER_SHARED_DATA
);
1369 KeAttachProcess(&Process
->Pcb
);
1370 //DPRINT1("Killing shared user data page no longer works -- has someone changed ARM3 in a way to make this fail now?\n");
1371 //MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
1372 //DPRINT1("Done\n");
1375 /* Acquire the PFN lock */
1376 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1378 /* Check for fully initialized process */
1379 if (Process
->AddressSpaceInitialized
== 2)
1381 /* Map the working set page and its page table */
1382 Pfn1
= MiGetPfnEntry(Process
->WorkingSetPage
);
1383 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1386 MI_SET_PFN_DELETED(Pfn1
);
1387 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1388 MiDecrementShareCount(Pfn1
, Process
->WorkingSetPage
);
1389 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1390 MiReleaseSystemPtes(MiAddressToPte(Process
->Vm
.VmWorkingSetList
), 1, SystemPteSpace
);
1392 /* Now map hyperspace and its page table */
1393 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[1] >> PAGE_SHIFT
;
1394 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1395 Pfn2
= MiGetPfnEntry(Pfn1
->u4
.PteFrame
);
1398 MI_SET_PFN_DELETED(Pfn1
);
1399 MiDecrementShareCount(Pfn2
, Pfn1
->u4
.PteFrame
);
1400 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1401 ASSERT((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
));
1403 /* Finally, nuke the PDE itself */
1404 PageFrameIndex
= Process
->Pcb
.DirectoryTableBase
[0] >> PAGE_SHIFT
;
1405 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1406 MI_SET_PFN_DELETED(Pfn1
);
1407 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1408 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
1410 /* HACK: In Richard's original patch this ASSERT did work */
1411 //DPRINT1("Ref count: %lx %lx\n", Pfn1->u3.e2.ReferenceCount, Pfn1->u2.ShareCount);
1412 //ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1413 if(!((Pfn1
->u3
.e2
.ReferenceCount
== 0) || (Pfn1
->u3
.e1
.WriteInProgress
)))
1414 DPRINT1("Ref count: %lx %lx\n", Pfn1
->u3
.e2
.ReferenceCount
, Pfn1
->u2
.ShareCount
);
1418 /* A partly-initialized process should never exit through here */
1422 /* Release the PFN lock */
1423 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1425 /* No support for sessions yet */
1426 ASSERT(Process
->Session
== 0);
1428 /* Clear out the PDE pages */
1429 Process
->Pcb
.DirectoryTableBase
[0] = 0;
1430 Process
->Pcb
.DirectoryTableBase
[1] = 0;
1433 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
1435 KGUARDED_MUTEX MiSessionIdMutex
;
1436 PRTL_BITMAP MiSessionIdBitmap
;
1437 volatile LONG MiSessionLeaderExists
;
1441 MiInitializeSessionIds(VOID
)
1443 /* FIXME: Other stuff should go here */
1445 /* Initialize the lock */
1446 KeInitializeGuardedMutex(&MiSessionIdMutex
);
1448 /* Allocate the bitmap */
1449 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
1450 sizeof(RTL_BITMAP
) + ((64 + 31) / 32) * 4,
1452 if (MiSessionIdBitmap
)
1454 /* Free all the bits */
1455 RtlInitializeBitMap(MiSessionIdBitmap
, (PVOID
)(MiSessionIdBitmap
+ 1), 64);
1456 RtlClearAllBits(MiSessionIdBitmap
);
1460 /* Die if we couldn't allocate the bitmap */
1461 KeBugCheckEx(INSTALL_MORE_MEMORY
,
1462 MmNumberOfPhysicalPages
,
1463 MmLowestPhysicalPage
,
1464 MmHighestPhysicalPage
,
1471 MiSessionLeader(IN PEPROCESS Process
)
1475 /* Set the flag while under the expansion lock */
1476 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
1477 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
1478 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
1483 MiSessionCreateInternal(OUT PULONG SessionId
)
1485 PEPROCESS Process
= PsGetCurrentProcess();
1486 ULONG NewFlags
, Flags
;
1488 /* Loop so we can set the session-is-creating flag */
1489 Flags
= Process
->Flags
;
1492 /* Check if it's already set */
1493 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
1496 DPRINT1("Lost session race\n");
1497 return STATUS_ALREADY_COMMITTED
;
1500 /* Now try to set it */
1501 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
1502 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
1504 if (NewFlags
== Flags
) break;
1506 /* It changed, try again */
1510 /* Now we should own the flag */
1511 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1513 /* Allocate a new Session ID */
1514 KeAcquireGuardedMutex(&MiSessionIdMutex
);
1515 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
1516 if (*SessionId
== 0xFFFFFFFF)
1518 DPRINT1("Too many sessions created. Expansion not yet supported\n");
1519 return STATUS_NO_MEMORY
;
1521 KeReleaseGuardedMutex(&MiSessionIdMutex
);
1523 /* We're done, clear the flag */
1524 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
1525 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
1526 return STATUS_SUCCESS
;
1531 MmSessionCreate(OUT PULONG SessionId
)
1533 PEPROCESS Process
= PsGetCurrentProcess();
1534 ULONG SessionLeaderExists
;
1537 /* Fail if the process is already in a session */
1538 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
1540 DPRINT1("Process already in session\n");
1541 return STATUS_ALREADY_COMMITTED
;
1544 /* Check if the process is already the session leader */
1545 if (!Process
->Vm
.Flags
.SessionLeader
)
1547 /* Atomically set it as the leader */
1548 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
1549 if (SessionLeaderExists
)
1551 DPRINT1("Session leader race\n");
1552 return STATUS_INVALID_SYSTEM_SERVICE
;
1555 /* Do the work required to upgrade him */
1556 MiSessionLeader(Process
);
1559 /* FIXME: Actually create a session */
1560 KeEnterCriticalRegion();
1561 Status
= MiSessionCreateInternal(SessionId
);
1562 KeLeaveCriticalRegion();
1564 /* Set and assert the flags, and return */
1565 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
1566 ASSERT(MiSessionLeaderExists
== 1);
1572 MmSessionDelete(IN ULONG SessionId
)
1574 PEPROCESS Process
= PsGetCurrentProcess();
1576 /* Process must be in a session */
1577 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
1579 DPRINT1("Not in a session!\n");
1580 return STATUS_UNABLE_TO_FREE_VM
;
1583 /* It must be the session leader */
1584 if (!Process
->Vm
.Flags
.SessionLeader
)
1586 DPRINT1("Not a session leader!\n");
1587 return STATUS_UNABLE_TO_FREE_VM
;
1590 /* Remove one reference count */
1591 KeEnterCriticalRegion();
1593 KeLeaveCriticalRegion();
1596 return STATUS_SUCCESS
;
1599 /* SYSTEM CALLS ***************************************************************/
1603 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
1604 IN OUT PULONG_PTR NumberOfPages
,
1605 IN OUT PULONG_PTR UserPfnArray
)
1608 return STATUS_NOT_IMPLEMENTED
;
1613 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
1614 IN ULONG_PTR NumberOfPages
,
1615 IN OUT PULONG_PTR UserPfnArray
)
1618 return STATUS_NOT_IMPLEMENTED
;
1623 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
1624 IN ULONG_PTR NumberOfPages
,
1625 IN OUT PULONG_PTR UserPfnArray
)
1628 return STATUS_NOT_IMPLEMENTED
;
1633 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
1634 IN OUT PULONG_PTR NumberOfPages
,
1635 IN OUT PULONG_PTR UserPfnArray
)
1638 return STATUS_NOT_IMPLEMENTED
;