[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / session.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
17
18 /* GLOBALS ********************************************************************/
19
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;
27
28
29 /* PRIVATE FUNCTIONS **********************************************************/
30
31 LCID
32 NTAPI
33 MmGetSessionLocaleId(VOID)
34 {
35 PEPROCESS Process;
36 PAGED_CODE();
37
38 //
39 // Get the current process
40 //
41 Process = PsGetCurrentProcess();
42
43 //
44 // Check if it's the Session Leader
45 //
46 if (Process->Vm.Flags.SessionLeader)
47 {
48 //
49 // Make sure it has a valid Session
50 //
51 if (Process->Session)
52 {
53 //
54 // Get the Locale ID
55 //
56 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
57 }
58 }
59
60 //
61 // Not a session leader, return the default
62 //
63 return PsDefaultThreadLocaleId;
64 }
65
66 VOID
67 NTAPI
68 MiInitializeSessionIds(VOID)
69 {
70 ULONG Size, BitmapSize;
71 PFN_NUMBER TotalPages;
72
73 /* Setup the total number of data pages needed for the structure */
74 TotalPages = MI_SESSION_DATA_PAGES_MAXIMUM;
75 MiSessionDataPages = ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE)) >> PAGE_SHIFT;
76 ASSERT(MiSessionDataPages <= MI_SESSION_DATA_PAGES_MAXIMUM - 3);
77 TotalPages -= MiSessionDataPages;
78
79 /* Setup the number of pages needed for session pool tags */
80 MiSessionTagSizePages = 2;
81 MiSessionBigPoolPages = 1;
82 MiSessionTagPages = MiSessionTagSizePages + MiSessionBigPoolPages;
83 ASSERT(MiSessionTagPages <= TotalPages);
84 ASSERT(MiSessionTagPages < MI_SESSION_TAG_PAGES_MAXIMUM);
85
86 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
87 MiSessionCreateCharge = 1 + MiSessionDataPages + MiSessionTagPages;
88
89 /* Initialize the lock */
90 KeInitializeGuardedMutex(&MiSessionIdMutex);
91
92 /* Allocate the bitmap */
93 Size = MI_INITIAL_SESSION_IDS;
94 BitmapSize = ((Size + 31) / 32) * sizeof(ULONG);
95 MiSessionIdBitmap = ExAllocatePoolWithTag(PagedPool,
96 sizeof(RTL_BITMAP) + BitmapSize,
97 ' mM');
98 if (MiSessionIdBitmap)
99 {
100 /* Free all the bits */
101 RtlInitializeBitMap(MiSessionIdBitmap,
102 (PVOID)(MiSessionIdBitmap + 1),
103 Size);
104 RtlClearAllBits(MiSessionIdBitmap);
105 }
106 else
107 {
108 /* Die if we couldn't allocate the bitmap */
109 KeBugCheckEx(INSTALL_MORE_MEMORY,
110 MmNumberOfPhysicalPages,
111 MmLowestPhysicalPage,
112 MmHighestPhysicalPage,
113 0x200);
114 }
115 }
116
117 VOID
118 NTAPI
119 MiSessionLeader(IN PEPROCESS Process)
120 {
121 KIRQL OldIrql;
122
123 /* Set the flag while under the expansion lock */
124 OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
125 Process->Vm.Flags.SessionLeader = TRUE;
126 KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
127 }
128
129 ULONG
130 NTAPI
131 MmGetSessionId(IN PEPROCESS Process)
132 {
133 PMM_SESSION_SPACE SessionGlobal;
134
135 /* The session leader is always session zero */
136 if (Process->Vm.Flags.SessionLeader == 1) return 0;
137
138 /* Otherwise, get the session global, and read the session ID from it */
139 SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
140 if (!SessionGlobal) return 0;
141 return SessionGlobal->SessionId;
142 }
143
144 ULONG
145 NTAPI
146 MmGetSessionIdEx(IN PEPROCESS Process)
147 {
148 PMM_SESSION_SPACE SessionGlobal;
149
150 /* The session leader is always session zero */
151 if (Process->Vm.Flags.SessionLeader == 1) return 0;
152
153 /* Otherwise, get the session global, and read the session ID from it */
154 SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
155 if (!SessionGlobal) return -1;
156 return SessionGlobal->SessionId;
157 }
158
159 VOID
160 NTAPI
161 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal)
162 {
163 ULONG i, SessionId;
164 PMMPTE PointerPte;
165 PFN_NUMBER PageFrameIndex[MI_SESSION_DATA_PAGES_MAXIMUM];
166 PMMPFN Pfn1;
167 KIRQL OldIrql;
168
169 /* Is there more than just this reference? If so, bail out */
170 if (InterlockedDecrement(&SessionGlobal->ProcessReferenceToSession)) return;
171
172 /* Get the session ID */
173 SessionId = SessionGlobal->SessionId;
174 DPRINT1("Last process in session %lu going down!!!\n", SessionId);
175
176 /* Free the session page tables */
177 #ifndef _M_AMD64
178 ExFreePoolWithTag(SessionGlobal->PageTables, 'tHmM');
179 #endif
180 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal));
181
182 /* Capture the data page PFNs */
183 PointerPte = MiAddressToPte(SessionGlobal);
184 for (i = 0; i < MiSessionDataPages; i++)
185 {
186 PageFrameIndex[i] = PFN_FROM_PTE(PointerPte + i);
187 }
188
189 /* Release them */
190 MiReleaseSystemPtes(PointerPte, MiSessionDataPages, SystemPteSpace);
191
192 /* Mark them as deleted */
193 for (i = 0; i < MiSessionDataPages; i++)
194 {
195 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
196 MI_SET_PFN_DELETED(Pfn1);
197 }
198
199 /* Loop every data page and drop a reference count */
200 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
201 for (i = 0; i < MiSessionDataPages; i++)
202 {
203 /* Sanity check that the page is correct, then decrement it */
204 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
205 ASSERT(Pfn1->u2.ShareCount == 1);
206 ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
207 MiDecrementShareCount(Pfn1, PageFrameIndex[i]);
208 }
209
210 /* Done playing with pages, release the lock */
211 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
212
213 /* Decrement the number of data pages */
214 InterlockedDecrement(&MmSessionDataPages);
215
216 /* Free this session ID from the session bitmap */
217 KeAcquireGuardedMutex(&MiSessionIdMutex);
218 ASSERT(RtlCheckBit(MiSessionIdBitmap, SessionId));
219 RtlClearBit(MiSessionIdBitmap, SessionId);
220 KeReleaseGuardedMutex(&MiSessionIdMutex);
221 }
222
223 VOID
224 NTAPI
225 MiSessionRemoveProcess(VOID)
226 {
227 PEPROCESS CurrentProcess = PsGetCurrentProcess();
228
229 /* If the process isn't already in a session, or if it's the leader... */
230 if (!(CurrentProcess->Flags & PSF_PROCESS_IN_SESSION_BIT) ||
231 (CurrentProcess->Vm.Flags.SessionLeader))
232 {
233 /* Then there's nothing to do */
234 return;
235 }
236
237 /* Sanity check */
238 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
239
240 /* Remove the process from the list ,and dereference the session */
241 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
242 //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
243 //MiDereferenceSession();
244 }
245
246 VOID
247 NTAPI
248 MiSessionAddProcess(IN PEPROCESS NewProcess)
249 {
250 PMM_SESSION_SPACE SessionGlobal;
251
252 /* The current process must already be in a session */
253 if (!(PsGetCurrentProcess()->Flags & PSF_PROCESS_IN_SESSION_BIT)) return;
254
255 /* Sanity check */
256 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
257
258 /* Get the global session */
259 SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
260
261 /* Increment counters */
262 InterlockedIncrement((PLONG)&SessionGlobal->ReferenceCount);
263 InterlockedIncrement(&SessionGlobal->ResidentProcessCount);
264 InterlockedIncrement(&SessionGlobal->ProcessReferenceToSession);
265
266 /* Set the session pointer */
267 ASSERT(NewProcess->Session == NULL);
268 NewProcess->Session = SessionGlobal;
269
270 /* Insert it into the process list */
271 // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
272 //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
273
274 /* Set the flag */
275 PspSetProcessFlag(NewProcess, PSF_PROCESS_IN_SESSION_BIT);
276 }
277
278 NTSTATUS
279 NTAPI
280 MiSessionInitializeWorkingSetList(VOID)
281 {
282 KIRQL OldIrql;
283 PMMPTE PointerPte, PointerPde;
284 MMPTE TempPte;
285 ULONG Color, Index;
286 PFN_NUMBER PageFrameIndex;
287 PMM_SESSION_SPACE SessionGlobal;
288 BOOLEAN AllocatedPageTable;
289 PMMWSL WorkingSetList;
290
291 /* Get pointers to session global and the session working set list */
292 SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
293 WorkingSetList = (PMMWSL)MiSessionSpaceWs;
294
295 /* Fill out the two pointers */
296 MmSessionSpace->Vm.VmWorkingSetList = WorkingSetList;
297 MmSessionSpace->Wsle = (PMMWSLE)WorkingSetList->UsedPageTableEntries;
298
299 /* Get the PDE for the working set, and check if it's already allocated */
300 PointerPde = MiAddressToPde(WorkingSetList);
301 if (PointerPde->u.Hard.Valid == 1)
302 {
303 /* Nope, we'll have to do it */
304 ASSERT(PointerPde->u.Hard.Global == 0);
305 AllocatedPageTable = FALSE;
306 }
307 else
308 {
309 /* Yep, that makes our job easier */
310 AllocatedPageTable = TRUE;
311 }
312
313 /* Get the PTE for the working set */
314 PointerPte = MiAddressToPte(WorkingSetList);
315
316 /* Initialize the working set lock, and lock the PFN database */
317 ExInitializePushLock(&SessionGlobal->Vm.WorkingSetMutex);
318 //MmLockPageableSectionByHandle(ExPageLockHandle);
319 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
320
321 /* Check if we need a page table */
322 if (AllocatedPageTable == TRUE)
323 {
324 /* Get a zeroed colored zero page */
325 Color = MI_GET_NEXT_COLOR();
326 PageFrameIndex = MiRemoveZeroPageSafe(Color);
327 if (!PageFrameIndex)
328 {
329 /* No zero pages, grab a free one */
330 PageFrameIndex = MiRemoveAnyPage(Color);
331
332 /* Zero it outside the PFN lock */
333 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
334 MiZeroPhysicalPage(PageFrameIndex);
335 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
336 }
337
338 /* Write a valid PDE for it */
339 TempPte.u.Long = ValidKernelPdeLocal.u.Long;
340 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
341 MI_WRITE_VALID_PTE(PointerPde, TempPte);
342
343 /* Add this into the list */
344 Index = ((ULONG_PTR)WorkingSetList - (ULONG_PTR)MmSessionBase) >> 22;
345 #ifndef _M_AMD64
346 MmSessionSpace->PageTables[Index] = TempPte;
347 #endif
348 /* Initialize the page directory page, and now zero the working set list itself */
349 MiInitializePfnForOtherProcess(PageFrameIndex,
350 PointerPde,
351 MmSessionSpace->SessionPageDirectoryIndex);
352 KeZeroPages(PointerPte, PAGE_SIZE);
353 }
354
355 /* Get a zeroed colored zero page */
356 Color = MI_GET_NEXT_COLOR();
357 PageFrameIndex = MiRemoveZeroPageSafe(Color);
358 if (!PageFrameIndex)
359 {
360 /* No zero pages, grab a free one */
361 PageFrameIndex = MiRemoveAnyPage(Color);
362
363 /* Zero it outside the PFN lock */
364 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
365 MiZeroPhysicalPage(PageFrameIndex);
366 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
367 }
368
369 /* Write a valid PTE for it */
370 TempPte.u.Long = ValidKernelPteLocal.u.Long;
371 TempPte.u.Hard.Dirty = TRUE;
372 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
373
374 /* Initialize the working set list page */
375 MiInitializePfnAndMakePteValid(PageFrameIndex, PointerPte, TempPte);
376
377 /* Now we can release the PFN database lock */
378 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
379
380 /* Fill out the working set structure */
381 MmSessionSpace->Vm.Flags.SessionSpace = 1;
382 MmSessionSpace->Vm.MinimumWorkingSetSize = 20;
383 MmSessionSpace->Vm.MaximumWorkingSetSize = 384;
384 WorkingSetList->LastEntry = 20;
385 WorkingSetList->HashTable = NULL;
386 WorkingSetList->HashTableSize = 0;
387 WorkingSetList->Wsle = MmSessionSpace->Wsle;
388
389 /* FIXME: Handle list insertions */
390 ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
391 ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
392 ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Flink == NULL);
393 ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Blink == NULL);
394
395 /* All done, return */
396 //MmUnlockPageableImageSection(ExPageLockHandle);
397 return STATUS_SUCCESS;
398 }
399
400 NTSTATUS
401 NTAPI
402 MiSessionCreateInternal(OUT PULONG SessionId)
403 {
404 PEPROCESS Process = PsGetCurrentProcess();
405 ULONG NewFlags, Flags, Size, i, Color;
406 KIRQL OldIrql;
407 PMMPTE PointerPte, PageTables, SessionPte;
408 PMMPDE PointerPde;
409 PMM_SESSION_SPACE SessionGlobal;
410 MMPTE TempPte;
411 NTSTATUS Status;
412 BOOLEAN Result;
413 PFN_NUMBER SessionPageDirIndex;
414 PFN_NUMBER TagPage[MI_SESSION_TAG_PAGES_MAXIMUM];
415 PFN_NUMBER DataPage[MI_SESSION_DATA_PAGES_MAXIMUM];
416
417 /* This should not exist yet */
418 ASSERT(MmIsAddressValid(MmSessionSpace) == FALSE);
419
420 /* Loop so we can set the session-is-creating flag */
421 Flags = Process->Flags;
422 while (TRUE)
423 {
424 /* Check if it's already set */
425 if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
426 {
427 /* Bail out */
428 DPRINT1("Lost session race\n");
429 return STATUS_ALREADY_COMMITTED;
430 }
431
432 /* Now try to set it */
433 NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
434 Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
435 Flags);
436 if (NewFlags == Flags) break;
437
438 /* It changed, try again */
439 Flags = NewFlags;
440 }
441
442 /* Now we should own the flag */
443 ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
444
445 /*
446 * Session space covers everything from 0xA0000000 to 0xC0000000.
447 * Allocate enough page tables to describe the entire region
448 */
449 Size = (0x20000000 / PDE_MAPPED_VA) * sizeof(MMPTE);
450 PageTables = ExAllocatePoolWithTag(NonPagedPool, Size, 'tHmM');
451 ASSERT(PageTables != NULL);
452 RtlZeroMemory(PageTables, Size);
453
454 /* Lock the session ID creation mutex */
455 KeAcquireGuardedMutex(&MiSessionIdMutex);
456
457 /* Allocate a new Session ID */
458 *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
459 if (*SessionId == 0xFFFFFFFF)
460 {
461 /* We ran out of session IDs, we should expand */
462 DPRINT1("Too many sessions created. Expansion not yet supported\n");
463 ExFreePoolWithTag(PageTables, 'tHmM');
464 return STATUS_NO_MEMORY;
465 }
466
467 /* Unlock the session ID creation mutex */
468 KeReleaseGuardedMutex(&MiSessionIdMutex);
469
470 /* Reserve the global PTEs */
471 SessionPte = MiReserveSystemPtes(MiSessionDataPages, SystemPteSpace);
472 ASSERT(SessionPte != NULL);
473
474 /* Acquire the PFN lock while we set everything up */
475 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
476
477 /* Loop the global PTEs */
478 TempPte.u.Long = ValidKernelPte.u.Long;
479 for (i = 0; i < MiSessionDataPages; i++)
480 {
481 /* Get a zeroed colored zero page */
482 Color = MI_GET_NEXT_COLOR();
483 DataPage[i] = MiRemoveZeroPageSafe(Color);
484 if (!DataPage[i])
485 {
486 /* No zero pages, grab a free one */
487 DataPage[i] = MiRemoveAnyPage(Color);
488
489 /* Zero it outside the PFN lock */
490 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
491 MiZeroPhysicalPage(DataPage[i]);
492 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
493 }
494
495 /* Fill the PTE out */
496 TempPte.u.Hard.PageFrameNumber = DataPage[i];
497 MI_WRITE_VALID_PTE(SessionPte + i, TempPte);
498 }
499
500 /* Set the pointer to global space */
501 SessionGlobal = MiPteToAddress(SessionPte);
502
503 /* Get a zeroed colored zero page */
504 Color = MI_GET_NEXT_COLOR();
505 SessionPageDirIndex = MiRemoveZeroPageSafe(Color);
506 if (!SessionPageDirIndex)
507 {
508 /* No zero pages, grab a free one */
509 SessionPageDirIndex = MiRemoveAnyPage(Color);
510
511 /* Zero it outside the PFN lock */
512 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
513 MiZeroPhysicalPage(SessionPageDirIndex);
514 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
515 }
516
517 /* Fill the PTE out */
518 TempPte.u.Long = ValidKernelPdeLocal.u.Long;
519 TempPte.u.Hard.PageFrameNumber = SessionPageDirIndex;
520
521 /* Setup, allocate, fill out the MmSessionSpace PTE */
522 PointerPde = MiAddressToPde(MmSessionSpace);
523 ASSERT(PointerPde->u.Long == 0);
524 MI_WRITE_VALID_PTE(PointerPde, TempPte);
525 MiInitializePfnForOtherProcess(SessionPageDirIndex,
526 PointerPde,
527 SessionPageDirIndex);
528 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex)->u1.WsIndex == 0);
529
530 /* Loop all the local PTEs for it */
531 TempPte.u.Long = ValidKernelPteLocal.u.Long;
532 PointerPte = MiAddressToPte(MmSessionSpace);
533 for (i = 0; i < MiSessionDataPages; i++)
534 {
535 /* And fill them out */
536 TempPte.u.Hard.PageFrameNumber = DataPage[i];
537 MiInitializePfnAndMakePteValid(DataPage[i], PointerPte + i, TempPte);
538 ASSERT(MI_PFN_ELEMENT(DataPage[i])->u1.WsIndex == 0);
539 }
540
541 /* Finally loop all of the session pool tag pages */
542 for (i = 0; i < MiSessionTagPages; i++)
543 {
544 /* Grab a zeroed colored page */
545 Color = MI_GET_NEXT_COLOR();
546 TagPage[i] = MiRemoveZeroPageSafe(Color);
547 if (!TagPage[i])
548 {
549 /* No zero pages, grab a free one */
550 TagPage[i] = MiRemoveAnyPage(Color);
551
552 /* Zero it outside the PFN lock */
553 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
554 MiZeroPhysicalPage(TagPage[i]);
555 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
556 }
557
558 /* Fill the PTE out */
559 TempPte.u.Hard.PageFrameNumber = TagPage[i];
560 MiInitializePfnAndMakePteValid(TagPage[i],
561 PointerPte + MiSessionDataPages + i,
562 TempPte);
563 }
564
565 /* PTEs have been setup, release the PFN lock */
566 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
567
568 /* Fill out the session space structure now */
569 MmSessionSpace->GlobalVirtualAddress = SessionGlobal;
570 MmSessionSpace->ReferenceCount = 1;
571 MmSessionSpace->ResidentProcessCount = 1;
572 MmSessionSpace->u.LongFlags = 0;
573 MmSessionSpace->SessionId = *SessionId;
574 MmSessionSpace->LocaleId = PsDefaultSystemLocaleId;
575 MmSessionSpace->SessionPageDirectoryIndex = SessionPageDirIndex;
576 MmSessionSpace->Color = Color;
577 MmSessionSpace->NonPageablePages = MiSessionCreateCharge;
578 MmSessionSpace->CommittedPages = MiSessionCreateCharge;
579 #ifndef _M_AMD64
580 MmSessionSpace->PageTables = PageTables;
581 MmSessionSpace->PageTables[PointerPde - MiAddressToPde(MmSessionBase)] = *PointerPde;
582 #endif
583 InitializeListHead(&MmSessionSpace->ImageList);
584 DPRINT1("Session %lu is ready to go: 0x%p 0x%p, %lx 0x%p\n",
585 *SessionId, MmSessionSpace, SessionGlobal, SessionPageDirIndex, PageTables);
586
587 /* Initialize session pool */
588 //Status = MiInitializeSessionPool();
589 Status = STATUS_SUCCESS;
590 ASSERT(NT_SUCCESS(Status) == TRUE);
591
592 /* Initialize system space */
593 Result = MiInitializeSystemSpaceMap(&SessionGlobal->Session);
594 ASSERT(Result == TRUE);
595
596 /* Initialize the process list, make sure the workign set list is empty */
597 ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
598 ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
599 InitializeListHead(&SessionGlobal->ProcessList);
600
601 /* We're done, clear the flag */
602 ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
603 PspClearProcessFlag(Process, PSF_SESSION_CREATION_UNDERWAY_BIT);
604
605 /* Insert the process into the session */
606 ASSERT(Process->Session == NULL);
607 ASSERT(SessionGlobal->ProcessReferenceToSession == 0);
608 SessionGlobal->ProcessReferenceToSession = 1;
609
610 /* We're done */
611 InterlockedIncrement(&MmSessionDataPages);
612 return STATUS_SUCCESS;
613 }
614
615 NTSTATUS
616 NTAPI
617 MmSessionCreate(OUT PULONG SessionId)
618 {
619 PEPROCESS Process = PsGetCurrentProcess();
620 ULONG SessionLeaderExists;
621 NTSTATUS Status;
622
623 /* Fail if the process is already in a session */
624 if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
625 {
626 DPRINT1("Process already in session\n");
627 return STATUS_ALREADY_COMMITTED;
628 }
629
630 /* Check if the process is already the session leader */
631 if (!Process->Vm.Flags.SessionLeader)
632 {
633 /* Atomically set it as the leader */
634 SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
635 if (SessionLeaderExists)
636 {
637 DPRINT1("Session leader race\n");
638 return STATUS_INVALID_SYSTEM_SERVICE;
639 }
640
641 /* Do the work required to upgrade him */
642 MiSessionLeader(Process);
643 }
644
645 /* Create the session */
646 KeEnterCriticalRegion();
647 Status = MiSessionCreateInternal(SessionId);
648 if (!NT_SUCCESS(Status))
649 {
650 KeLeaveCriticalRegion();
651 return Status;
652 }
653
654 /* Set up the session working set */
655 Status = MiSessionInitializeWorkingSetList();
656 if (!NT_SUCCESS(Status))
657 {
658 /* Fail */
659 //MiDereferenceSession();
660 ASSERT(FALSE);
661 KeLeaveCriticalRegion();
662 return Status;
663 }
664
665 /* All done */
666 KeLeaveCriticalRegion();
667
668 /* Set and assert the flags, and return */
669 MmSessionSpace->u.Flags.Initialized = 1;
670 PspSetProcessFlag(Process, PSF_PROCESS_IN_SESSION_BIT);
671 ASSERT(MiSessionLeaderExists == 1);
672 return Status;
673 }
674
675 NTSTATUS
676 NTAPI
677 MmSessionDelete(IN ULONG SessionId)
678 {
679 PEPROCESS Process = PsGetCurrentProcess();
680
681 /* Process must be in a session */
682 if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
683 {
684 DPRINT1("Not in a session!\n");
685 return STATUS_UNABLE_TO_FREE_VM;
686 }
687
688 /* It must be the session leader */
689 if (!Process->Vm.Flags.SessionLeader)
690 {
691 DPRINT1("Not a session leader!\n");
692 return STATUS_UNABLE_TO_FREE_VM;
693 }
694
695 /* Remove one reference count */
696 KeEnterCriticalRegion();
697 /* FIXME: Do it */
698 KeLeaveCriticalRegion();
699
700 /* All done */
701 return STATUS_SUCCESS;
702 }