[NTOSKRNK]
[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 // HACK: we support only one process. The creator is CSRSS and that lives!
29 PEPROCESS Session0CreatorProcess;
30
31
32 /* PRIVATE FUNCTIONS **********************************************************/
33
34 LCID
35 NTAPI
36 MmGetSessionLocaleId(VOID)
37 {
38 PEPROCESS Process;
39 PAGED_CODE();
40
41 //
42 // Get the current process
43 //
44 Process = PsGetCurrentProcess();
45
46 //
47 // Check if it's the Session Leader
48 //
49 if (Process->Vm.Flags.SessionLeader)
50 {
51 //
52 // Make sure it has a valid Session
53 //
54 if (Process->Session)
55 {
56 //
57 // Get the Locale ID
58 //
59 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
60 }
61 }
62
63 //
64 // Not a session leader, return the default
65 //
66 return PsDefaultThreadLocaleId;
67 }
68
69 VOID
70 NTAPI
71 MiInitializeSessionIds(VOID)
72 {
73 ULONG Size, BitmapSize;
74 PFN_NUMBER TotalPages;
75
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;
81
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);
88
89 /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
90 MiSessionCreateCharge = 1 + MiSessionDataPages + MiSessionTagPages;
91
92 /* Initialize the lock */
93 KeInitializeGuardedMutex(&MiSessionIdMutex);
94
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,
100 ' mM');
101 if (MiSessionIdBitmap)
102 {
103 /* Free all the bits */
104 RtlInitializeBitMap(MiSessionIdBitmap,
105 (PVOID)(MiSessionIdBitmap + 1),
106 Size);
107 RtlClearAllBits(MiSessionIdBitmap);
108 }
109 else
110 {
111 /* Die if we couldn't allocate the bitmap */
112 KeBugCheckEx(INSTALL_MORE_MEMORY,
113 MmNumberOfPhysicalPages,
114 MmLowestPhysicalPage,
115 MmHighestPhysicalPage,
116 0x200);
117 }
118 }
119
120 VOID
121 NTAPI
122 MiSessionLeader(IN PEPROCESS Process)
123 {
124 KIRQL OldIrql;
125
126 /* Set the flag while under the expansion lock */
127 OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
128 Process->Vm.Flags.SessionLeader = TRUE;
129 KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
130 }
131
132 ULONG
133 NTAPI
134 MmGetSessionId(IN PEPROCESS Process)
135 {
136 PMM_SESSION_SPACE SessionGlobal;
137
138 /* The session leader is always session zero */
139 if (Process->Vm.Flags.SessionLeader == 1) return 0;
140
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;
145 }
146
147 ULONG
148 NTAPI
149 MmGetSessionIdEx(IN PEPROCESS Process)
150 {
151 PMM_SESSION_SPACE SessionGlobal;
152
153 /* The session leader is always session zero */
154 if (Process->Vm.Flags.SessionLeader == 1) return 0;
155
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;
160 }
161
162 VOID
163 NTAPI
164 MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal)
165 {
166 ULONG i, SessionId;
167 PMMPTE PointerPte;
168 PFN_NUMBER PageFrameIndex[MI_SESSION_DATA_PAGES_MAXIMUM];
169 PMMPFN Pfn1;
170 KIRQL OldIrql;
171
172 /* Is there more than just this reference? If so, bail out */
173 if (InterlockedDecrement(&SessionGlobal->ProcessReferenceToSession)) return;
174
175 /* Get the session ID */
176 SessionId = SessionGlobal->SessionId;
177 DPRINT1("Last process in session %lu going down!!!\n", SessionId);
178
179 /* Free the session page tables */
180 #ifndef _M_AMD64
181 ExFreePoolWithTag(SessionGlobal->PageTables, 'tHmM');
182 #endif
183 ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal));
184
185 /* Capture the data page PFNs */
186 PointerPte = MiAddressToPte(SessionGlobal);
187 for (i = 0; i < MiSessionDataPages; i++)
188 {
189 PageFrameIndex[i] = PFN_FROM_PTE(PointerPte + i);
190 }
191
192 /* Release them */
193 MiReleaseSystemPtes(PointerPte, MiSessionDataPages, SystemPteSpace);
194
195 /* Mark them as deleted */
196 for (i = 0; i < MiSessionDataPages; i++)
197 {
198 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
199 MI_SET_PFN_DELETED(Pfn1);
200 }
201
202 /* Loop every data page and drop a reference count */
203 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
204 for (i = 0; i < MiSessionDataPages; i++)
205 {
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]);
211 }
212
213 /* Done playing with pages, release the lock */
214 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
215
216 /* Decrement the number of data pages */
217 InterlockedDecrement(&MmSessionDataPages);
218
219 /* Free this session ID from the session bitmap */
220 KeAcquireGuardedMutex(&MiSessionIdMutex);
221 ASSERT(RtlCheckBit(MiSessionIdBitmap, SessionId));
222 RtlClearBit(MiSessionIdBitmap, SessionId);
223 KeReleaseGuardedMutex(&MiSessionIdMutex);
224 }
225
226 VOID
227 NTAPI
228 MiSessionRemoveProcess(VOID)
229 {
230 PEPROCESS CurrentProcess = PsGetCurrentProcess();
231
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))
235 {
236 /* Then there's nothing to do */
237 return;
238 }
239
240 /* Sanity check */
241 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
242
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();
247 }
248
249 VOID
250 NTAPI
251 MiSessionAddProcess(IN PEPROCESS NewProcess)
252 {
253 PMM_SESSION_SPACE SessionGlobal;
254
255 /* The current process must already be in a session */
256 if (!(PsGetCurrentProcess()->Flags & PSF_PROCESS_IN_SESSION_BIT)) return;
257
258 /* Sanity check */
259 ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
260
261 /* Get the global session */
262 SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
263
264 /* Increment counters */
265 InterlockedIncrement((PLONG)&SessionGlobal->ReferenceCount);
266 InterlockedIncrement(&SessionGlobal->ResidentProcessCount);
267 InterlockedIncrement(&SessionGlobal->ProcessReferenceToSession);
268
269 /* Set the session pointer */
270 ASSERT(NewProcess->Session == NULL);
271 NewProcess->Session = SessionGlobal;
272
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);
276
277 /* Set the flag */
278 PspSetProcessFlag(NewProcess, PSF_PROCESS_IN_SESSION_BIT);
279 }
280
281 NTSTATUS
282 NTAPI
283 MiSessionInitializeWorkingSetList(VOID)
284 {
285 KIRQL OldIrql;
286 PMMPTE PointerPte, PointerPde;
287 MMPTE TempPte;
288 ULONG Color, Index;
289 PFN_NUMBER PageFrameIndex;
290 PMM_SESSION_SPACE SessionGlobal;
291 BOOLEAN AllocatedPageTable;
292 PMMWSL WorkingSetList;
293
294 /* Get pointers to session global and the session working set list */
295 SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
296 WorkingSetList = (PMMWSL)MiSessionSpaceWs;
297
298 /* Fill out the two pointers */
299 MmSessionSpace->Vm.VmWorkingSetList = WorkingSetList;
300 MmSessionSpace->Wsle = (PMMWSLE)WorkingSetList->UsedPageTableEntries;
301
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)
305 {
306 /* Nope, we'll have to do it */
307 ASSERT(PointerPde->u.Hard.Global == 0);
308 AllocatedPageTable = FALSE;
309 }
310 else
311 {
312 /* Yep, that makes our job easier */
313 AllocatedPageTable = TRUE;
314 }
315
316 /* Get the PTE for the working set */
317 PointerPte = MiAddressToPte(WorkingSetList);
318
319 /* Initialize the working set lock, and lock the PFN database */
320 ExInitializePushLock(&SessionGlobal->Vm.WorkingSetMutex);
321 //MmLockPageableSectionByHandle(ExPageLockHandle);
322 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
323
324 /* Check if we need a page table */
325 if (AllocatedPageTable == TRUE)
326 {
327 /* Get a zeroed colored zero page */
328 Color = MI_GET_NEXT_COLOR();
329 PageFrameIndex = MiRemoveZeroPageSafe(Color);
330 if (!PageFrameIndex)
331 {
332 /* No zero pages, grab a free one */
333 PageFrameIndex = MiRemoveAnyPage(Color);
334
335 /* Zero it outside the PFN lock */
336 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
337 MiZeroPhysicalPage(PageFrameIndex);
338 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
339 }
340
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);
345
346 /* Add this into the list */
347 Index = ((ULONG_PTR)WorkingSetList - (ULONG_PTR)MmSessionBase) >> 22;
348 #ifndef _M_AMD64
349 MmSessionSpace->PageTables[Index] = TempPte;
350 #endif
351 /* Initialize the page directory page, and now zero the working set list itself */
352 MiInitializePfnForOtherProcess(PageFrameIndex,
353 PointerPde,
354 MmSessionSpace->SessionPageDirectoryIndex);
355 KeZeroPages(PointerPte, PAGE_SIZE);
356 }
357
358 /* Get a zeroed colored zero page */
359 Color = MI_GET_NEXT_COLOR();
360 PageFrameIndex = MiRemoveZeroPageSafe(Color);
361 if (!PageFrameIndex)
362 {
363 /* No zero pages, grab a free one */
364 PageFrameIndex = MiRemoveAnyPage(Color);
365
366 /* Zero it outside the PFN lock */
367 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
368 MiZeroPhysicalPage(PageFrameIndex);
369 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
370 }
371
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;
376
377 /* Initialize the working set list page */
378 MiInitializePfnAndMakePteValid(PageFrameIndex, PointerPte, TempPte);
379
380 /* Now we can release the PFN database lock */
381 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
382
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;
391
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);
397
398 /* All done, return */
399 //MmUnlockPageableImageSection(ExPageLockHandle);
400 return STATUS_SUCCESS;
401 }
402
403 NTSTATUS
404 NTAPI
405 MiSessionCreateInternal(OUT PULONG SessionId)
406 {
407 PEPROCESS Process = PsGetCurrentProcess();
408 ULONG NewFlags, Flags, Size, i, Color;
409 KIRQL OldIrql;
410 PMMPTE PointerPte, PageTables, SessionPte;
411 PMMPDE PointerPde;
412 PMM_SESSION_SPACE SessionGlobal;
413 MMPTE TempPte;
414 NTSTATUS Status;
415 BOOLEAN Result;
416 PFN_NUMBER SessionPageDirIndex;
417 PFN_NUMBER TagPage[MI_SESSION_TAG_PAGES_MAXIMUM];
418 PFN_NUMBER DataPage[MI_SESSION_DATA_PAGES_MAXIMUM];
419
420 /* This should not exist yet */
421 ASSERT(MmIsAddressValid(MmSessionSpace) == FALSE);
422
423 /* Loop so we can set the session-is-creating flag */
424 Flags = Process->Flags;
425 while (TRUE)
426 {
427 /* Check if it's already set */
428 if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
429 {
430 /* Bail out */
431 DPRINT1("Lost session race\n");
432 return STATUS_ALREADY_COMMITTED;
433 }
434
435 /* Now try to set it */
436 NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
437 Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
438 Flags);
439 if (NewFlags == Flags) break;
440
441 /* It changed, try again */
442 Flags = NewFlags;
443 }
444
445 /* Now we should own the flag */
446 ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
447
448 /*
449 * Session space covers everything from 0xA0000000 to 0xC0000000.
450 * Allocate enough page tables to describe the entire region
451 */
452 Size = (0x20000000 / PDE_MAPPED_VA) * sizeof(MMPTE);
453 PageTables = ExAllocatePoolWithTag(NonPagedPool, Size, 'tHmM');
454 ASSERT(PageTables != NULL);
455 RtlZeroMemory(PageTables, Size);
456
457 /* Lock the session ID creation mutex */
458 KeAcquireGuardedMutex(&MiSessionIdMutex);
459
460 /* Allocate a new Session ID */
461 *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
462 if (*SessionId == 0xFFFFFFFF)
463 {
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;
468 }
469
470 /* Unlock the session ID creation mutex */
471 KeReleaseGuardedMutex(&MiSessionIdMutex);
472
473 /* Reserve the global PTEs */
474 SessionPte = MiReserveSystemPtes(MiSessionDataPages, SystemPteSpace);
475 ASSERT(SessionPte != NULL);
476
477 /* Acquire the PFN lock while we set everything up */
478 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
479
480 /* Loop the global PTEs */
481 TempPte.u.Long = ValidKernelPte.u.Long;
482 for (i = 0; i < MiSessionDataPages; i++)
483 {
484 /* Get a zeroed colored zero page */
485 Color = MI_GET_NEXT_COLOR();
486 DataPage[i] = MiRemoveZeroPageSafe(Color);
487 if (!DataPage[i])
488 {
489 /* No zero pages, grab a free one */
490 DataPage[i] = MiRemoveAnyPage(Color);
491
492 /* Zero it outside the PFN lock */
493 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
494 MiZeroPhysicalPage(DataPage[i]);
495 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
496 }
497
498 /* Fill the PTE out */
499 TempPte.u.Hard.PageFrameNumber = DataPage[i];
500 MI_WRITE_VALID_PTE(SessionPte + i, TempPte);
501 }
502
503 /* Set the pointer to global space */
504 SessionGlobal = MiPteToAddress(SessionPte);
505
506 /* Get a zeroed colored zero page */
507 Color = MI_GET_NEXT_COLOR();
508 SessionPageDirIndex = MiRemoveZeroPageSafe(Color);
509 if (!SessionPageDirIndex)
510 {
511 /* No zero pages, grab a free one */
512 SessionPageDirIndex = MiRemoveAnyPage(Color);
513
514 /* Zero it outside the PFN lock */
515 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
516 MiZeroPhysicalPage(SessionPageDirIndex);
517 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
518 }
519
520 /* Fill the PTE out */
521 TempPte.u.Long = ValidKernelPdeLocal.u.Long;
522 TempPte.u.Hard.PageFrameNumber = SessionPageDirIndex;
523
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,
529 PointerPde,
530 SessionPageDirIndex);
531 ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex)->u1.WsIndex == 0);
532
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++)
537 {
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);
542 }
543
544 /* Finally loop all of the session pool tag pages */
545 for (i = 0; i < MiSessionTagPages; i++)
546 {
547 /* Grab a zeroed colored page */
548 Color = MI_GET_NEXT_COLOR();
549 TagPage[i] = MiRemoveZeroPageSafe(Color);
550 if (!TagPage[i])
551 {
552 /* No zero pages, grab a free one */
553 TagPage[i] = MiRemoveAnyPage(Color);
554
555 /* Zero it outside the PFN lock */
556 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
557 MiZeroPhysicalPage(TagPage[i]);
558 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
559 }
560
561 /* Fill the PTE out */
562 TempPte.u.Hard.PageFrameNumber = TagPage[i];
563 MiInitializePfnAndMakePteValid(TagPage[i],
564 PointerPte + MiSessionDataPages + i,
565 TempPte);
566 }
567
568 /* PTEs have been setup, release the PFN lock */
569 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
570
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;
582 #ifndef _M_AMD64
583 MmSessionSpace->PageTables = PageTables;
584 MmSessionSpace->PageTables[PointerPde - MiAddressToPde(MmSessionBase)] = *PointerPde;
585 #endif
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);
589
590 /* Initialize session pool */
591 //Status = MiInitializeSessionPool();
592 Status = STATUS_SUCCESS;
593 ASSERT(NT_SUCCESS(Status) == TRUE);
594
595 /* Initialize system space */
596 Result = MiInitializeSystemSpaceMap(&SessionGlobal->Session);
597 ASSERT(Result == TRUE);
598
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);
603
604 /* We're done, clear the flag */
605 ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
606 PspClearProcessFlag(Process, PSF_SESSION_CREATION_UNDERWAY_BIT);
607
608 /* Insert the process into the session */
609 ASSERT(Process->Session == NULL);
610 ASSERT(SessionGlobal->ProcessReferenceToSession == 0);
611 SessionGlobal->ProcessReferenceToSession = 1;
612
613 // HACK: we only support 1 session and save the creator process
614 NT_ASSERT(Session0CreatorProcess == NULL);
615 Session0CreatorProcess = PsGetCurrentProcess();
616
617 /* We're done */
618 InterlockedIncrement(&MmSessionDataPages);
619 return STATUS_SUCCESS;
620 }
621
622 NTSTATUS
623 NTAPI
624 MmSessionCreate(OUT PULONG SessionId)
625 {
626 PEPROCESS Process = PsGetCurrentProcess();
627 ULONG SessionLeaderExists;
628 NTSTATUS Status;
629
630 /* Fail if the process is already in a session */
631 if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
632 {
633 DPRINT1("Process already in session\n");
634 return STATUS_ALREADY_COMMITTED;
635 }
636
637 /* Check if the process is already the session leader */
638 if (!Process->Vm.Flags.SessionLeader)
639 {
640 /* Atomically set it as the leader */
641 SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
642 if (SessionLeaderExists)
643 {
644 DPRINT1("Session leader race\n");
645 return STATUS_INVALID_SYSTEM_SERVICE;
646 }
647
648 /* Do the work required to upgrade him */
649 MiSessionLeader(Process);
650 }
651
652 /* Create the session */
653 KeEnterCriticalRegion();
654 Status = MiSessionCreateInternal(SessionId);
655 if (!NT_SUCCESS(Status))
656 {
657 KeLeaveCriticalRegion();
658 return Status;
659 }
660
661 /* Set up the session working set */
662 Status = MiSessionInitializeWorkingSetList();
663 if (!NT_SUCCESS(Status))
664 {
665 /* Fail */
666 //MiDereferenceSession();
667 ASSERT(FALSE);
668 KeLeaveCriticalRegion();
669 return Status;
670 }
671
672 /* All done */
673 KeLeaveCriticalRegion();
674
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);
679 return Status;
680 }
681
682 NTSTATUS
683 NTAPI
684 MmSessionDelete(IN ULONG SessionId)
685 {
686 PEPROCESS Process = PsGetCurrentProcess();
687
688 /* Process must be in a session */
689 if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
690 {
691 DPRINT1("Not in a session!\n");
692 return STATUS_UNABLE_TO_FREE_VM;
693 }
694
695 /* It must be the session leader */
696 if (!Process->Vm.Flags.SessionLeader)
697 {
698 DPRINT1("Not a session leader!\n");
699 return STATUS_UNABLE_TO_FREE_VM;
700 }
701
702 /* Remove one reference count */
703 KeEnterCriticalRegion();
704 /* FIXME: Do it */
705 KeLeaveCriticalRegion();
706
707 /* All done */
708 return STATUS_SUCCESS;
709 }
710
711 _IRQL_requires_max_(APC_LEVEL)
712 NTSTATUS
713 NTAPI
714 MmAttachSession(
715 _Inout_ PVOID SessionEntry,
716 _Out_ PKAPC_STATE ApcState)
717 {
718 PEPROCESS EntryProcess;
719
720 /* The parameter is the actual process! */
721 EntryProcess = SessionEntry;
722 NT_ASSERT(EntryProcess != NULL);
723
724 /* HACK: for now we only support 1 session! */
725 NT_ASSERT(((PMM_SESSION_SPACE)EntryProcess->Session)->SessionId == 1);
726
727 /* Very simple for now: just attach to the process we have */
728 KeStackAttachProcess(&EntryProcess->Pcb, ApcState);
729 return STATUS_SUCCESS;
730 }
731
732 _IRQL_requires_max_(APC_LEVEL)
733 VOID
734 NTAPI
735 MmDetachSession(
736 _Inout_ PVOID SessionEntry,
737 _In_ PKAPC_STATE ApcState)
738 {
739 PEPROCESS EntryProcess;
740
741 /* The parameter is the actual process! */
742 EntryProcess = SessionEntry;
743 NT_ASSERT(EntryProcess != NULL);
744
745 /* HACK: for now we only support 1 session! */
746 NT_ASSERT(((PMM_SESSION_SPACE)EntryProcess->Session)->SessionId == 0);
747
748 /* Very simple for now: just detach */
749 KeUnstackDetachProcess(ApcState);
750 }
751
752 VOID
753 NTAPI
754 MmQuitNextSession(
755 _Inout_ PVOID SessionEntry)
756 {
757 PEPROCESS EntryProcess;
758
759 /* The parameter is the actual process! */
760 EntryProcess = SessionEntry;
761 NT_ASSERT(EntryProcess != NULL);
762
763 /* HACK: for now we only support 1 session! */
764 NT_ASSERT(((PMM_SESSION_SPACE)EntryProcess->Session)->SessionId == 0);
765
766 /* Get rid of the reference we got */
767 ObDereferenceObject(SessionEntry);
768 }
769
770 PVOID
771 NTAPI
772 MmGetSessionById(
773 _In_ ULONG SessionId)
774 {
775 /* HACK: for now we only support 1 session! */
776 NT_ASSERT(SessionId == 0);
777
778 /* Just return the sessions creator process, which is csrss and still alive. */
779 return Session0CreatorProcess;
780 }