2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/session.c
5 * PURPOSE: Session support routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
18 /* GLOBALS ********************************************************************/
20 PMM_SESSION_SPACE MmSessionSpace
;
21 PFN_NUMBER MiSessionDataPages
, MiSessionTagPages
, MiSessionTagSizePages
;
22 PFN_NUMBER MiSessionBigPoolPages
, MiSessionCreateCharge
;
23 KGUARDED_MUTEX MiSessionIdMutex
;
24 LONG MmSessionDataPages
;
25 PRTL_BITMAP MiSessionIdBitmap
;
26 volatile LONG MiSessionLeaderExists
;
28 // HACK: we support only one process. The creator is CSRSS and that lives!
29 PEPROCESS Session0CreatorProcess
;
32 /* PRIVATE FUNCTIONS **********************************************************/
36 MmGetSessionLocaleId(VOID
)
42 // Get the current process
44 Process
= PsGetCurrentProcess();
47 // Check if it's the Session Leader
49 if (Process
->Vm
.Flags
.SessionLeader
)
52 // Make sure it has a valid Session
59 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
64 // Not a session leader, return the default
66 return PsDefaultThreadLocaleId
;
71 MiInitializeSessionIds(VOID
)
73 ULONG Size
, BitmapSize
;
74 PFN_NUMBER TotalPages
;
76 /* Setup the total number of data pages needed for the structure */
77 TotalPages
= MI_SESSION_DATA_PAGES_MAXIMUM
;
78 MiSessionDataPages
= ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE
)) >> PAGE_SHIFT
;
79 ASSERT(MiSessionDataPages
<= MI_SESSION_DATA_PAGES_MAXIMUM
- 3);
80 TotalPages
-= MiSessionDataPages
;
82 /* Setup the number of pages needed for session pool tags */
83 MiSessionTagSizePages
= 2;
84 MiSessionBigPoolPages
= 1;
85 MiSessionTagPages
= MiSessionTagSizePages
+ MiSessionBigPoolPages
;
86 ASSERT(MiSessionTagPages
<= TotalPages
);
87 ASSERT(MiSessionTagPages
< MI_SESSION_TAG_PAGES_MAXIMUM
);
89 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
90 MiSessionCreateCharge
= 1 + MiSessionDataPages
+ MiSessionTagPages
;
92 /* Initialize the lock */
93 KeInitializeGuardedMutex(&MiSessionIdMutex
);
95 /* Allocate the bitmap */
96 Size
= MI_INITIAL_SESSION_IDS
;
97 BitmapSize
= ((Size
+ 31) / 32) * sizeof(ULONG
);
98 MiSessionIdBitmap
= ExAllocatePoolWithTag(PagedPool
,
99 sizeof(RTL_BITMAP
) + BitmapSize
,
101 if (MiSessionIdBitmap
)
103 /* Free all the bits */
104 RtlInitializeBitMap(MiSessionIdBitmap
,
105 (PVOID
)(MiSessionIdBitmap
+ 1),
107 RtlClearAllBits(MiSessionIdBitmap
);
111 /* Die if we couldn't allocate the bitmap */
112 KeBugCheckEx(INSTALL_MORE_MEMORY
,
113 MmNumberOfPhysicalPages
,
114 MmLowestPhysicalPage
,
115 MmHighestPhysicalPage
,
122 MiSessionLeader(IN PEPROCESS Process
)
126 /* Set the flag while under the expansion lock */
127 OldIrql
= KeAcquireQueuedSpinLock(LockQueueExpansionLock
);
128 Process
->Vm
.Flags
.SessionLeader
= TRUE
;
129 KeReleaseQueuedSpinLock(LockQueueExpansionLock
, OldIrql
);
134 MmGetSessionId(IN PEPROCESS Process
)
136 PMM_SESSION_SPACE SessionGlobal
;
138 /* The session leader is always session zero */
139 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
141 /* Otherwise, get the session global, and read the session ID from it */
142 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
143 if (!SessionGlobal
) return 0;
144 return SessionGlobal
->SessionId
;
149 MmGetSessionIdEx(IN PEPROCESS Process
)
151 PMM_SESSION_SPACE SessionGlobal
;
153 /* The session leader is always session zero */
154 if (Process
->Vm
.Flags
.SessionLeader
== 1) return 0;
156 /* Otherwise, get the session global, and read the session ID from it */
157 SessionGlobal
= (PMM_SESSION_SPACE
)Process
->Session
;
158 if (!SessionGlobal
) return -1;
159 return SessionGlobal
->SessionId
;
164 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal
)
168 PFN_NUMBER PageFrameIndex
[MI_SESSION_DATA_PAGES_MAXIMUM
];
172 /* Is there more than just this reference? If so, bail out */
173 if (InterlockedDecrement(&SessionGlobal
->ProcessReferenceToSession
)) return;
175 /* Get the session ID */
176 SessionId
= SessionGlobal
->SessionId
;
177 DPRINT1("Last process in session %lu going down!!!\n", SessionId
);
179 /* Free the session page tables */
181 ExFreePoolWithTag(SessionGlobal
->PageTables
, 'tHmM');
183 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal
));
185 /* Capture the data page PFNs */
186 PointerPte
= MiAddressToPte(SessionGlobal
);
187 for (i
= 0; i
< MiSessionDataPages
; i
++)
189 PageFrameIndex
[i
] = PFN_FROM_PTE(PointerPte
+ i
);
193 MiReleaseSystemPtes(PointerPte
, MiSessionDataPages
, SystemPteSpace
);
195 /* Mark them as deleted */
196 for (i
= 0; i
< MiSessionDataPages
; i
++)
198 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
199 MI_SET_PFN_DELETED(Pfn1
);
202 /* Loop every data page and drop a reference count */
203 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
204 for (i
= 0; i
< MiSessionDataPages
; i
++)
206 /* Sanity check that the page is correct, then decrement it */
207 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
[i
]);
208 ASSERT(Pfn1
->u2
.ShareCount
== 1);
209 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 1);
210 MiDecrementShareCount(Pfn1
, PageFrameIndex
[i
]);
213 /* Done playing with pages, release the lock */
214 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
216 /* Decrement the number of data pages */
217 InterlockedDecrement(&MmSessionDataPages
);
219 /* Free this session ID from the session bitmap */
220 KeAcquireGuardedMutex(&MiSessionIdMutex
);
221 ASSERT(RtlCheckBit(MiSessionIdBitmap
, SessionId
));
222 RtlClearBit(MiSessionIdBitmap
, SessionId
);
223 KeReleaseGuardedMutex(&MiSessionIdMutex
);
228 MiSessionRemoveProcess(VOID
)
230 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
232 /* If the process isn't already in a session, or if it's the leader... */
233 if (!(CurrentProcess
->Flags
& PSF_PROCESS_IN_SESSION_BIT
) ||
234 (CurrentProcess
->Vm
.Flags
.SessionLeader
))
236 /* Then there's nothing to do */
241 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
243 /* Remove the process from the list ,and dereference the session */
244 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
245 //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
246 //MiDereferenceSession();
251 MiSessionAddProcess(IN PEPROCESS NewProcess
)
253 PMM_SESSION_SPACE SessionGlobal
;
255 /* The current process must already be in a session */
256 if (!(PsGetCurrentProcess()->Flags
& PSF_PROCESS_IN_SESSION_BIT
)) return;
259 ASSERT(MmIsAddressValid(MmSessionSpace
) == TRUE
);
261 /* Get the global session */
262 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
264 /* Increment counters */
265 InterlockedIncrement((PLONG
)&SessionGlobal
->ReferenceCount
);
266 InterlockedIncrement(&SessionGlobal
->ResidentProcessCount
);
267 InterlockedIncrement(&SessionGlobal
->ProcessReferenceToSession
);
269 /* Set the session pointer */
270 ASSERT(NewProcess
->Session
== NULL
);
271 NewProcess
->Session
= SessionGlobal
;
273 /* Insert it into the process list */
274 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
275 //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
278 PspSetProcessFlag(NewProcess
, PSF_PROCESS_IN_SESSION_BIT
);
283 MiSessionInitializeWorkingSetList(VOID
)
286 PMMPTE PointerPte
, PointerPde
;
289 PFN_NUMBER PageFrameIndex
;
290 PMM_SESSION_SPACE SessionGlobal
;
291 BOOLEAN AllocatedPageTable
;
292 PMMWSL WorkingSetList
;
294 /* Get pointers to session global and the session working set list */
295 SessionGlobal
= MmSessionSpace
->GlobalVirtualAddress
;
296 WorkingSetList
= (PMMWSL
)MiSessionSpaceWs
;
298 /* Fill out the two pointers */
299 MmSessionSpace
->Vm
.VmWorkingSetList
= WorkingSetList
;
300 MmSessionSpace
->Wsle
= (PMMWSLE
)WorkingSetList
->UsedPageTableEntries
;
302 /* Get the PDE for the working set, and check if it's already allocated */
303 PointerPde
= MiAddressToPde(WorkingSetList
);
304 if (PointerPde
->u
.Hard
.Valid
== 1)
306 /* Nope, we'll have to do it */
307 ASSERT(PointerPde
->u
.Hard
.Global
== 0);
308 AllocatedPageTable
= FALSE
;
312 /* Yep, that makes our job easier */
313 AllocatedPageTable
= TRUE
;
316 /* Get the PTE for the working set */
317 PointerPte
= MiAddressToPte(WorkingSetList
);
319 /* Initialize the working set lock, and lock the PFN database */
320 ExInitializePushLock(&SessionGlobal
->Vm
.WorkingSetMutex
);
321 //MmLockPageableSectionByHandle(ExPageLockHandle);
322 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
324 /* Check if we need a page table */
325 if (AllocatedPageTable
== TRUE
)
327 /* Get a zeroed colored zero page */
328 Color
= MI_GET_NEXT_COLOR();
329 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
332 /* No zero pages, grab a free one */
333 PageFrameIndex
= MiRemoveAnyPage(Color
);
335 /* Zero it outside the PFN lock */
336 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
337 MiZeroPhysicalPage(PageFrameIndex
);
338 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
341 /* Write a valid PDE for it */
342 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
343 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
344 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
346 /* Add this into the list */
347 Index
= ((ULONG_PTR
)WorkingSetList
- (ULONG_PTR
)MmSessionBase
) >> 22;
349 MmSessionSpace
->PageTables
[Index
] = TempPte
;
351 /* Initialize the page directory page, and now zero the working set list itself */
352 MiInitializePfnForOtherProcess(PageFrameIndex
,
354 MmSessionSpace
->SessionPageDirectoryIndex
);
355 KeZeroPages(PointerPte
, PAGE_SIZE
);
358 /* Get a zeroed colored zero page */
359 Color
= MI_GET_NEXT_COLOR();
360 PageFrameIndex
= MiRemoveZeroPageSafe(Color
);
363 /* No zero pages, grab a free one */
364 PageFrameIndex
= MiRemoveAnyPage(Color
);
366 /* Zero it outside the PFN lock */
367 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
368 MiZeroPhysicalPage(PageFrameIndex
);
369 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
372 /* Write a valid PTE for it */
373 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
374 TempPte
.u
.Hard
.Dirty
= TRUE
;
375 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
377 /* Initialize the working set list page */
378 MiInitializePfnAndMakePteValid(PageFrameIndex
, PointerPte
, TempPte
);
380 /* Now we can release the PFN database lock */
381 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
383 /* Fill out the working set structure */
384 MmSessionSpace
->Vm
.Flags
.SessionSpace
= 1;
385 MmSessionSpace
->Vm
.MinimumWorkingSetSize
= 20;
386 MmSessionSpace
->Vm
.MaximumWorkingSetSize
= 384;
387 WorkingSetList
->LastEntry
= 20;
388 WorkingSetList
->HashTable
= NULL
;
389 WorkingSetList
->HashTableSize
= 0;
390 WorkingSetList
->Wsle
= MmSessionSpace
->Wsle
;
392 /* FIXME: Handle list insertions */
393 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
394 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
395 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Flink
== NULL
);
396 ASSERT(SessionGlobal
->Vm
.WorkingSetExpansionLinks
.Blink
== NULL
);
398 /* All done, return */
399 //MmUnlockPageableImageSection(ExPageLockHandle);
400 return STATUS_SUCCESS
;
405 MiSessionCreateInternal(OUT PULONG SessionId
)
407 PEPROCESS Process
= PsGetCurrentProcess();
408 ULONG NewFlags
, Flags
, Size
, i
, Color
;
410 PMMPTE PointerPte
, PageTables
, SessionPte
;
412 PMM_SESSION_SPACE SessionGlobal
;
416 PFN_NUMBER SessionPageDirIndex
;
417 PFN_NUMBER TagPage
[MI_SESSION_TAG_PAGES_MAXIMUM
];
418 PFN_NUMBER DataPage
[MI_SESSION_DATA_PAGES_MAXIMUM
];
420 /* This should not exist yet */
421 ASSERT(MmIsAddressValid(MmSessionSpace
) == FALSE
);
423 /* Loop so we can set the session-is-creating flag */
424 Flags
= Process
->Flags
;
427 /* Check if it's already set */
428 if (Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
)
431 DPRINT1("Lost session race\n");
432 return STATUS_ALREADY_COMMITTED
;
435 /* Now try to set it */
436 NewFlags
= InterlockedCompareExchange((PLONG
)&Process
->Flags
,
437 Flags
| PSF_SESSION_CREATION_UNDERWAY_BIT
,
439 if (NewFlags
== Flags
) break;
441 /* It changed, try again */
445 /* Now we should own the flag */
446 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
449 * Session space covers everything from 0xA0000000 to 0xC0000000.
450 * Allocate enough page tables to describe the entire region
452 Size
= (0x20000000 / PDE_MAPPED_VA
) * sizeof(MMPTE
);
453 PageTables
= ExAllocatePoolWithTag(NonPagedPool
, Size
, 'tHmM');
454 ASSERT(PageTables
!= NULL
);
455 RtlZeroMemory(PageTables
, Size
);
457 /* Lock the session ID creation mutex */
458 KeAcquireGuardedMutex(&MiSessionIdMutex
);
460 /* Allocate a new Session ID */
461 *SessionId
= RtlFindClearBitsAndSet(MiSessionIdBitmap
, 1, 0);
462 if (*SessionId
== 0xFFFFFFFF)
464 /* We ran out of session IDs, we should expand */
465 DPRINT1("Too many sessions created. Expansion not yet supported\n");
466 ExFreePoolWithTag(PageTables
, 'tHmM');
467 return STATUS_NO_MEMORY
;
470 /* Unlock the session ID creation mutex */
471 KeReleaseGuardedMutex(&MiSessionIdMutex
);
473 /* Reserve the global PTEs */
474 SessionPte
= MiReserveSystemPtes(MiSessionDataPages
, SystemPteSpace
);
475 ASSERT(SessionPte
!= NULL
);
477 /* Acquire the PFN lock while we set everything up */
478 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
480 /* Loop the global PTEs */
481 TempPte
.u
.Long
= ValidKernelPte
.u
.Long
;
482 for (i
= 0; i
< MiSessionDataPages
; i
++)
484 /* Get a zeroed colored zero page */
485 Color
= MI_GET_NEXT_COLOR();
486 DataPage
[i
] = MiRemoveZeroPageSafe(Color
);
489 /* No zero pages, grab a free one */
490 DataPage
[i
] = MiRemoveAnyPage(Color
);
492 /* Zero it outside the PFN lock */
493 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
494 MiZeroPhysicalPage(DataPage
[i
]);
495 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
498 /* Fill the PTE out */
499 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
500 MI_WRITE_VALID_PTE(SessionPte
+ i
, TempPte
);
503 /* Set the pointer to global space */
504 SessionGlobal
= MiPteToAddress(SessionPte
);
506 /* Get a zeroed colored zero page */
507 Color
= MI_GET_NEXT_COLOR();
508 SessionPageDirIndex
= MiRemoveZeroPageSafe(Color
);
509 if (!SessionPageDirIndex
)
511 /* No zero pages, grab a free one */
512 SessionPageDirIndex
= MiRemoveAnyPage(Color
);
514 /* Zero it outside the PFN lock */
515 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
516 MiZeroPhysicalPage(SessionPageDirIndex
);
517 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
520 /* Fill the PTE out */
521 TempPte
.u
.Long
= ValidKernelPdeLocal
.u
.Long
;
522 TempPte
.u
.Hard
.PageFrameNumber
= SessionPageDirIndex
;
524 /* Setup, allocate, fill out the MmSessionSpace PTE */
525 PointerPde
= MiAddressToPde(MmSessionSpace
);
526 ASSERT(PointerPde
->u
.Long
== 0);
527 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
528 MiInitializePfnForOtherProcess(SessionPageDirIndex
,
530 SessionPageDirIndex
);
531 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex
)->u1
.WsIndex
== 0);
533 /* Loop all the local PTEs for it */
534 TempPte
.u
.Long
= ValidKernelPteLocal
.u
.Long
;
535 PointerPte
= MiAddressToPte(MmSessionSpace
);
536 for (i
= 0; i
< MiSessionDataPages
; i
++)
538 /* And fill them out */
539 TempPte
.u
.Hard
.PageFrameNumber
= DataPage
[i
];
540 MiInitializePfnAndMakePteValid(DataPage
[i
], PointerPte
+ i
, TempPte
);
541 ASSERT(MI_PFN_ELEMENT(DataPage
[i
])->u1
.WsIndex
== 0);
544 /* Finally loop all of the session pool tag pages */
545 for (i
= 0; i
< MiSessionTagPages
; i
++)
547 /* Grab a zeroed colored page */
548 Color
= MI_GET_NEXT_COLOR();
549 TagPage
[i
] = MiRemoveZeroPageSafe(Color
);
552 /* No zero pages, grab a free one */
553 TagPage
[i
] = MiRemoveAnyPage(Color
);
555 /* Zero it outside the PFN lock */
556 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
557 MiZeroPhysicalPage(TagPage
[i
]);
558 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
561 /* Fill the PTE out */
562 TempPte
.u
.Hard
.PageFrameNumber
= TagPage
[i
];
563 MiInitializePfnAndMakePteValid(TagPage
[i
],
564 PointerPte
+ MiSessionDataPages
+ i
,
568 /* PTEs have been setup, release the PFN lock */
569 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
571 /* Fill out the session space structure now */
572 MmSessionSpace
->GlobalVirtualAddress
= SessionGlobal
;
573 MmSessionSpace
->ReferenceCount
= 1;
574 MmSessionSpace
->ResidentProcessCount
= 1;
575 MmSessionSpace
->u
.LongFlags
= 0;
576 MmSessionSpace
->SessionId
= *SessionId
;
577 MmSessionSpace
->LocaleId
= PsDefaultSystemLocaleId
;
578 MmSessionSpace
->SessionPageDirectoryIndex
= SessionPageDirIndex
;
579 MmSessionSpace
->Color
= Color
;
580 MmSessionSpace
->NonPageablePages
= MiSessionCreateCharge
;
581 MmSessionSpace
->CommittedPages
= MiSessionCreateCharge
;
583 MmSessionSpace
->PageTables
= PageTables
;
584 MmSessionSpace
->PageTables
[PointerPde
- MiAddressToPde(MmSessionBase
)] = *PointerPde
;
586 InitializeListHead(&MmSessionSpace
->ImageList
);
587 DPRINT1("Session %lu is ready to go: 0x%p 0x%p, %lx 0x%p\n",
588 *SessionId
, MmSessionSpace
, SessionGlobal
, SessionPageDirIndex
, PageTables
);
590 /* Initialize session pool */
591 //Status = MiInitializeSessionPool();
592 Status
= STATUS_SUCCESS
;
593 ASSERT(NT_SUCCESS(Status
) == TRUE
);
595 /* Initialize system space */
596 Result
= MiInitializeSystemSpaceMap(&SessionGlobal
->Session
);
597 ASSERT(Result
== TRUE
);
599 /* Initialize the process list, make sure the workign set list is empty */
600 ASSERT(SessionGlobal
->WsListEntry
.Flink
== NULL
);
601 ASSERT(SessionGlobal
->WsListEntry
.Blink
== NULL
);
602 InitializeListHead(&SessionGlobal
->ProcessList
);
604 /* We're done, clear the flag */
605 ASSERT(Process
->Flags
& PSF_SESSION_CREATION_UNDERWAY_BIT
);
606 PspClearProcessFlag(Process
, PSF_SESSION_CREATION_UNDERWAY_BIT
);
608 /* Insert the process into the session */
609 ASSERT(Process
->Session
== NULL
);
610 ASSERT(SessionGlobal
->ProcessReferenceToSession
== 0);
611 SessionGlobal
->ProcessReferenceToSession
= 1;
613 // HACK: we only support 1 session and save the creator process
614 NT_ASSERT(Session0CreatorProcess
== NULL
);
615 Session0CreatorProcess
= PsGetCurrentProcess();
618 InterlockedIncrement(&MmSessionDataPages
);
619 return STATUS_SUCCESS
;
624 MmSessionCreate(OUT PULONG SessionId
)
626 PEPROCESS Process
= PsGetCurrentProcess();
627 ULONG SessionLeaderExists
;
630 /* Fail if the process is already in a session */
631 if (Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
)
633 DPRINT1("Process already in session\n");
634 return STATUS_ALREADY_COMMITTED
;
637 /* Check if the process is already the session leader */
638 if (!Process
->Vm
.Flags
.SessionLeader
)
640 /* Atomically set it as the leader */
641 SessionLeaderExists
= InterlockedCompareExchange(&MiSessionLeaderExists
, 1, 0);
642 if (SessionLeaderExists
)
644 DPRINT1("Session leader race\n");
645 return STATUS_INVALID_SYSTEM_SERVICE
;
648 /* Do the work required to upgrade him */
649 MiSessionLeader(Process
);
652 /* Create the session */
653 KeEnterCriticalRegion();
654 Status
= MiSessionCreateInternal(SessionId
);
655 if (!NT_SUCCESS(Status
))
657 KeLeaveCriticalRegion();
661 /* Set up the session working set */
662 Status
= MiSessionInitializeWorkingSetList();
663 if (!NT_SUCCESS(Status
))
666 //MiDereferenceSession();
668 KeLeaveCriticalRegion();
673 KeLeaveCriticalRegion();
675 /* Set and assert the flags, and return */
676 MmSessionSpace
->u
.Flags
.Initialized
= 1;
677 PspSetProcessFlag(Process
, PSF_PROCESS_IN_SESSION_BIT
);
678 ASSERT(MiSessionLeaderExists
== 1);
684 MmSessionDelete(IN ULONG SessionId
)
686 PEPROCESS Process
= PsGetCurrentProcess();
688 /* Process must be in a session */
689 if (!(Process
->Flags
& PSF_PROCESS_IN_SESSION_BIT
))
691 DPRINT1("Not in a session!\n");
692 return STATUS_UNABLE_TO_FREE_VM
;
695 /* It must be the session leader */
696 if (!Process
->Vm
.Flags
.SessionLeader
)
698 DPRINT1("Not a session leader!\n");
699 return STATUS_UNABLE_TO_FREE_VM
;
702 /* Remove one reference count */
703 KeEnterCriticalRegion();
705 KeLeaveCriticalRegion();
708 return STATUS_SUCCESS
;
711 _IRQL_requires_max_(APC_LEVEL
)
715 _Inout_ PVOID SessionEntry
,
716 _Out_ PKAPC_STATE ApcState
)
718 PEPROCESS EntryProcess
;
720 /* The parameter is the actual process! */
721 EntryProcess
= SessionEntry
;
722 NT_ASSERT(EntryProcess
!= NULL
);
724 /* HACK: for now we only support 1 session! */
725 NT_ASSERT(((PMM_SESSION_SPACE
)EntryProcess
->Session
)->SessionId
== 1);
727 /* Very simple for now: just attach to the process we have */
728 KeStackAttachProcess(&EntryProcess
->Pcb
, ApcState
);
729 return STATUS_SUCCESS
;
732 _IRQL_requires_max_(APC_LEVEL
)
736 _Inout_ PVOID SessionEntry
,
737 _In_ PKAPC_STATE ApcState
)
739 PEPROCESS EntryProcess
;
741 /* The parameter is the actual process! */
742 EntryProcess
= SessionEntry
;
743 NT_ASSERT(EntryProcess
!= NULL
);
745 /* HACK: for now we only support 1 session! */
746 NT_ASSERT(((PMM_SESSION_SPACE
)EntryProcess
->Session
)->SessionId
== 0);
748 /* Very simple for now: just detach */
749 KeUnstackDetachProcess(ApcState
);
755 _Inout_ PVOID SessionEntry
)
757 PEPROCESS EntryProcess
;
759 /* The parameter is the actual process! */
760 EntryProcess
= SessionEntry
;
761 NT_ASSERT(EntryProcess
!= NULL
);
763 /* HACK: for now we only support 1 session! */
764 NT_ASSERT(((PMM_SESSION_SPACE
)EntryProcess
->Session
)->SessionId
== 0);
766 /* Get rid of the reference we got */
767 ObDereferenceObject(SessionEntry
);
773 _In_ ULONG SessionId
)
775 /* HACK: for now we only support 1 session! */
776 NT_ASSERT(SessionId
== 0);
778 /* Just return the sessions creator process, which is csrss and still alive. */
779 return Session0CreatorProcess
;