[NTOSKRNL/MM]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / procsup.c
1 /*
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
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 ULONG MmProcessColorSeed = 0x12345678;
21 PMMWSL MmWorkingSetList;
22
23 /* PRIVATE FUNCTIONS **********************************************************/
24
25 VOID
26 NTAPI
27 MiRosTakeOverSharedUserPage(IN PEPROCESS Process)
28 {
29 NTSTATUS Status;
30 PMEMORY_AREA MemoryArea;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple;
32 PVOID AllocatedBase = (PVOID)MM_SHARED_USER_DATA_VA;
33 BoundaryAddressMultiple.QuadPart = 0;
34
35 Status = MmCreateMemoryArea(&Process->Vm,
36 MEMORY_AREA_OWNED_BY_ARM3,
37 &AllocatedBase,
38 PAGE_SIZE,
39 PAGE_READWRITE,
40 &MemoryArea,
41 TRUE,
42 0,
43 BoundaryAddressMultiple);
44 ASSERT(NT_SUCCESS(Status));
45 }
46
47 NTSTATUS
48 NTAPI
49 MiCreatePebOrTeb(IN PEPROCESS Process,
50 IN ULONG Size,
51 OUT PULONG_PTR Base)
52 {
53 PETHREAD Thread = PsGetCurrentThread();
54 PMMVAD_LONG Vad;
55 NTSTATUS Status;
56 ULONG RandomCoeff;
57 ULONG_PTR StartAddress, EndAddress;
58 LARGE_INTEGER CurrentTime;
59 TABLE_SEARCH_RESULT Result = TableFoundNode;
60 PMMADDRESS_NODE Parent;
61
62 /* Allocate a VAD */
63 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
64 if (!Vad) return STATUS_NO_MEMORY;
65
66 /* Setup the primary flags with the size, and make it commited, private, RW */
67 Vad->u.LongFlags = 0;
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;
73
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;
79
80 /* Lock the process address space */
81 KeAcquireGuardedMutex(&Process->AddressCreationLock);
82
83 /* Check if this is a PEB creation */
84 if (Size == sizeof(PEB))
85 {
86 /* Start at the highest valid address */
87 StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
88
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;
94
95 /* Select the highest valid address minus the random coefficient */
96 StartAddress -= RandomCoeff;
97 EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
98
99 /* Try to find something below the random upper margin */
100 Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
101 EndAddress,
102 PAGE_SIZE,
103 &Process->VadRoot,
104 Base,
105 &Parent);
106 }
107
108 /* Check for success. TableFoundNode means nothing free. */
109 if (Result == TableFoundNode)
110 {
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,
114 PAGE_SIZE,
115 &Process->VadRoot,
116 Base,
117 &Parent);
118 /* Bail out, if still nothing free was found */
119 if (Result == TableFoundNode) return STATUS_NO_MEMORY;
120 }
121
122 /* Validate that it came from the VAD ranges */
123 ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
124
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;
131
132 /* FIXME: Should setup VAD bitmap */
133 Status = STATUS_SUCCESS;
134
135 /* Pretend as if we own the working set */
136 MiLockProcessWorkingSet(Process, Thread);
137
138 /* Insert the VAD */
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);
146
147 /* Release the working set */
148 MiUnlockProcessWorkingSet(Process, Thread);
149
150 /* Release the address space lock */
151 KeReleaseGuardedMutex(&Process->AddressCreationLock);
152
153 /* Return the status */
154 return Status;
155 }
156
157 VOID
158 NTAPI
159 MmDeleteTeb(IN PEPROCESS Process,
160 IN PTEB Teb)
161 {
162 ULONG_PTR TebEnd;
163 PETHREAD Thread = PsGetCurrentThread();
164 PMMVAD Vad;
165 PMM_AVL_TABLE VadTree = &Process->VadRoot;
166 DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
167
168 /* TEB is one page */
169 TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
170
171 /* Attach to the process */
172 KeAttachProcess(&Process->Pcb);
173
174 /* Lock the process address space */
175 KeAcquireGuardedMutex(&Process->AddressCreationLock);
176
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);
180 ASSERT(Vad != NULL);
181 if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
182 {
183 /* Bug in the AVL code? */
184 DPRINT1("Corrupted VAD!\n");
185 }
186 else
187 {
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);
194
195 /* Lock the working set */
196 MiLockProcessWorkingSet(Process, Thread);
197
198 /* Remove this VAD from the tree */
199 ASSERT(VadTree->NumberGenericTableElements >= 1);
200 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
201
202 /* Delete the pages */
203 MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL);
204
205 /* Release the working set */
206 MiUnlockProcessWorkingSet(Process, Thread);
207
208 /* Remove the VAD */
209 ExFreePool(Vad);
210 }
211
212 /* Release the address space lock */
213 KeReleaseGuardedMutex(&Process->AddressCreationLock);
214
215 /* Detach */
216 KeDetachProcess();
217 }
218
219 VOID
220 NTAPI
221 MmDeleteKernelStack(IN PVOID StackBase,
222 IN BOOLEAN GuiStack)
223 {
224 PMMPTE PointerPte;
225 PFN_NUMBER PageFrameNumber, PageTableFrameNumber;
226 PFN_COUNT StackPages;
227 PMMPFN Pfn1;//, Pfn2;
228 ULONG i;
229 KIRQL OldIrql;
230
231 //
232 // This should be the guard page, so decrement by one
233 //
234 PointerPte = MiAddressToPte(StackBase);
235 PointerPte--;
236
237 //
238 // Calculate pages used
239 //
240 StackPages = BYTES_TO_PAGES(GuiStack ?
241 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
242
243 /* Acquire the PFN lock */
244 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
245
246 //
247 // Loop them
248 //
249 for (i = 0; i < StackPages; i++)
250 {
251 //
252 // Check if this is a valid PTE
253 //
254 if (PointerPte->u.Hard.Valid == 1)
255 {
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);
263
264 /* Remove a shared reference, since the page is going away */
265 DPRINT("SystemPTE PDE: %lx\n", PageTableFrameNumber);
266 //MiDecrementShareCount(Pfn2, PageTableFrameNumber);
267 #endif
268 /* Set the special pending delete marker */
269 MI_SET_PFN_DELETED(Pfn1);
270
271 /* And now delete the actual stack page */
272 MiDecrementShareCount(Pfn1, PageFrameNumber);
273 }
274
275 //
276 // Next one
277 //
278 PointerPte--;
279 }
280
281 //
282 // We should be at the guard page now
283 //
284 ASSERT(PointerPte->u.Hard.Valid == 0);
285
286 /* Release the PFN lock */
287 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
288
289 //
290 // Release the PTEs
291 //
292 MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace);
293 }
294
295 PVOID
296 NTAPI
297 MmCreateKernelStack(IN BOOLEAN GuiStack,
298 IN UCHAR Node)
299 {
300 PFN_COUNT StackPtes, StackPages;
301 PMMPTE PointerPte, StackPte;
302 PVOID BaseAddress;
303 MMPTE TempPte, InvalidPte;
304 KIRQL OldIrql;
305 PFN_NUMBER PageFrameIndex;
306 ULONG i;
307
308 //
309 // Calculate pages needed
310 //
311 if (GuiStack)
312 {
313 //
314 // We'll allocate 64KB stack, but only commit 12K
315 //
316 StackPtes = BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE);
317 StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT);
318
319 }
320 else
321 {
322 //
323 // We'll allocate 12K and that's it
324 //
325 StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE);
326 StackPages = StackPtes;
327 }
328
329 //
330 // Reserve stack pages, plus a guard page
331 //
332 StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace);
333 if (!StackPte) return NULL;
334
335 //
336 // Get the stack address
337 //
338 BaseAddress = MiPteToAddress(StackPte + StackPtes + 1);
339
340 //
341 // Select the right PTE address where we actually start committing pages
342 //
343 PointerPte = StackPte;
344 if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE -
345 KERNEL_LARGE_STACK_COMMIT);
346
347
348 /* Setup the temporary invalid PTE */
349 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
350
351 /* Setup the template stack PTE */
352 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
353
354 //
355 // Acquire the PFN DB lock
356 //
357 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
358
359 //
360 // Loop each stack page
361 //
362 for (i = 0; i < StackPages; i++)
363 {
364 //
365 // Next PTE
366 //
367 PointerPte++;
368
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);
374
375 /* Initialize the PFN entry for this page */
376 MiInitializePfn(PageFrameIndex, PointerPte, 1);
377
378 /* Write the valid PTE */
379 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
380 MI_WRITE_VALID_PTE(PointerPte, TempPte);
381 }
382
383 //
384 // Release the PFN lock
385 //
386 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
387
388 //
389 // Return the stack address
390 //
391 return BaseAddress;
392 }
393
394 NTSTATUS
395 NTAPI
396 MmGrowKernelStackEx(IN PVOID StackPointer,
397 IN ULONG GrowSize)
398 {
399 PKTHREAD Thread = KeGetCurrentThread();
400 PMMPTE LimitPte, NewLimitPte, LastPte;
401 KIRQL OldIrql;
402 MMPTE TempPte, InvalidPte;
403 PFN_NUMBER PageFrameIndex;
404
405 //
406 // Make sure the stack did not overflow
407 //
408 ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
409 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
410
411 //
412 // Get the current stack limit
413 //
414 LimitPte = MiAddressToPte(Thread->StackLimit);
415 ASSERT(LimitPte->u.Hard.Valid == 1);
416
417 //
418 // Get the new one and make sure this isn't a retarded request
419 //
420 NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
421 if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
422
423 //
424 // Now make sure you're not going past the reserved space
425 //
426 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
427 KERNEL_LARGE_STACK_SIZE));
428 if (NewLimitPte < LastPte)
429 {
430 //
431 // Sorry!
432 //
433 DPRINT1("Thread wants too much stack\n");
434 return STATUS_STACK_OVERFLOW;
435 }
436
437 //
438 // Calculate the number of new pages
439 //
440 LimitPte--;
441
442 /* Setup the temporary invalid PTE */
443 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
444
445 //
446 // Acquire the PFN DB lock
447 //
448 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
449
450 //
451 // Loop each stack page
452 //
453 while (LimitPte >= NewLimitPte)
454 {
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);
460
461 /* Initialize the PFN entry for this page */
462 MiInitializePfn(PageFrameIndex, LimitPte, 1);
463
464 /* Setup the template stack PTE */
465 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
466
467 /* Write the valid PTE */
468 MI_WRITE_VALID_PTE(LimitPte--, TempPte);
469 }
470
471 //
472 // Release the PFN lock
473 //
474 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
475
476 //
477 // Set the new limit
478 //
479 Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
480 return STATUS_SUCCESS;
481 }
482
483 NTSTATUS
484 NTAPI
485 MmGrowKernelStack(IN PVOID StackPointer)
486 {
487 //
488 // Call the extended version
489 //
490 return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
491 }
492
493 NTSTATUS
494 NTAPI
495 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
496 IN UCHAR MemoryPriority)
497 {
498 UCHAR OldPriority;
499
500 //
501 // Check if we have less then 16MB of Physical Memory
502 //
503 if ((MmSystemSize == MmSmallSystem) &&
504 (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
505 {
506 //
507 // Always use background priority
508 //
509 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
510 }
511
512 //
513 // Save the old priority and update it
514 //
515 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
516 Process->Vm.Flags.MemoryPriority = MemoryPriority;
517
518 //
519 // Return the old priority
520 //
521 return OldPriority;
522 }
523
524 LCID
525 NTAPI
526 MmGetSessionLocaleId(VOID)
527 {
528 PEPROCESS Process;
529 PAGED_CODE();
530
531 //
532 // Get the current process
533 //
534 Process = PsGetCurrentProcess();
535
536 //
537 // Check if it's the Session Leader
538 //
539 if (Process->Vm.Flags.SessionLeader)
540 {
541 //
542 // Make sure it has a valid Session
543 //
544 if (Process->Session)
545 {
546 //
547 // Get the Locale ID
548 //
549 #if ROS_HAS_SESSIONS
550 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
551 #endif
552 }
553 }
554
555 //
556 // Not a session leader, return the default
557 //
558 return PsDefaultThreadLocaleId;
559 }
560
561 NTSTATUS
562 NTAPI
563 MmCreatePeb(IN PEPROCESS Process,
564 IN PINITIAL_PEB InitialPeb,
565 OUT PPEB *BasePeb)
566 {
567 PPEB Peb = NULL;
568 LARGE_INTEGER SectionOffset;
569 SIZE_T ViewSize = 0;
570 PVOID TableBase = NULL;
571 PIMAGE_NT_HEADERS NtHeaders;
572 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
573 NTSTATUS Status;
574 USHORT Characteristics;
575 KAFFINITY ProcessAffinityMask = 0;
576 SectionOffset.QuadPart = (ULONGLONG)0;
577 *BasePeb = NULL;
578
579 //
580 // Attach to Process
581 //
582 KeAttachProcess(&Process->Pcb);
583
584 //
585 // Map NLS Tables
586 //
587 Status = MmMapViewOfSection(ExpNlsSectionPointer,
588 (PEPROCESS)Process,
589 &TableBase,
590 0,
591 0,
592 &SectionOffset,
593 &ViewSize,
594 ViewShare,
595 MEM_TOP_DOWN,
596 PAGE_READONLY);
597 DPRINT("NLS Tables at: %p\n", TableBase);
598 if (!NT_SUCCESS(Status))
599 {
600 /* Cleanup and exit */
601 KeDetachProcess();
602 return Status;
603 }
604
605 //
606 // Allocate the PEB
607 //
608 Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
609 DPRINT("PEB at: %p\n", Peb);
610 if (!NT_SUCCESS(Status))
611 {
612 /* Cleanup and exit */
613 KeDetachProcess();
614 return Status;
615 }
616
617 //
618 // Use SEH in case we can't load the PEB
619 //
620 _SEH2_TRY
621 {
622 //
623 // Initialize the PEB
624 //
625 RtlZeroMemory(Peb, sizeof(PEB));
626
627 //
628 // Set up data
629 //
630 Peb->ImageBaseAddress = Process->SectionBaseAddress;
631 Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
632 Peb->Mutant = InitialPeb->Mutant;
633 Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
634
635 //
636 // NLS
637 //
638 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
639 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
640 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
641
642 //
643 // Default Version Data (could get changed below)
644 //
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;
650
651 //
652 // Heap and Debug Data
653 //
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;
663 */
664 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
665 Peb->ProcessHeaps = (PVOID*)(Peb + 1);
666
667 //
668 // Session ID
669 //
670 if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
671 }
672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
673 {
674 //
675 // Fail
676 //
677 KeDetachProcess();
678 _SEH2_YIELD(return _SEH2_GetExceptionCode());
679 }
680 _SEH2_END;
681
682 //
683 // Use SEH in case we can't load the image
684 //
685 _SEH2_TRY
686 {
687 //
688 // Get NT Headers
689 //
690 NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
691 Characteristics = NtHeaders->FileHeader.Characteristics;
692 }
693 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
694 {
695 //
696 // Fail
697 //
698 KeDetachProcess();
699 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
700 }
701 _SEH2_END;
702
703 //
704 // Parse the headers
705 //
706 if (NtHeaders)
707 {
708 //
709 // Use SEH in case we can't load the headers
710 //
711 _SEH2_TRY
712 {
713 //
714 // Get the Image Config Data too
715 //
716 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
717 TRUE,
718 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
719 (PULONG)&ViewSize);
720 if (ImageConfigData)
721 {
722 //
723 // Probe it
724 //
725 ProbeForRead(ImageConfigData,
726 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
727 sizeof(ULONG));
728 }
729
730 //
731 // Write subsystem data
732 //
733 Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
734 Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
735 Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
736
737 //
738 // Check for version data
739 //
740 if (NtHeaders->OptionalHeader.Win32VersionValue)
741 {
742 //
743 // Extract values and write them
744 //
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;
749
750 /* Process CSD version override */
751 if ((ImageConfigData) && (ImageConfigData->CSDVersion))
752 {
753 /* Take the value from the image configuration directory */
754 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
755 }
756 }
757
758 /* Process optional process affinity mask override */
759 if ((ImageConfigData) && (ImageConfigData->ProcessAffinityMask))
760 {
761 /* Take the value from the image configuration directory */
762 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
763 }
764
765 //
766 // Check if this is a UP image
767 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
768 {
769 //
770 // Force it to use CPU 0
771 //
772 /* FIXME: this should use the MmRotatingUniprocessorNumber */
773 Peb->ImageProcessAffinityMask = 0;
774 }
775 else
776 {
777 //
778 // Whatever was configured
779 //
780 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
781 }
782 }
783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
784 {
785 //
786 // Fail
787 //
788 KeDetachProcess();
789 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
790 }
791 _SEH2_END;
792 }
793
794 //
795 // Detach from the Process
796 //
797 KeDetachProcess();
798 *BasePeb = Peb;
799 return STATUS_SUCCESS;
800 }
801
802 NTSTATUS
803 NTAPI
804 MmCreateTeb(IN PEPROCESS Process,
805 IN PCLIENT_ID ClientId,
806 IN PINITIAL_TEB InitialTeb,
807 OUT PTEB *BaseTeb)
808 {
809 PTEB Teb;
810 NTSTATUS Status = STATUS_SUCCESS;
811 *BaseTeb = NULL;
812
813 //
814 // Attach to Target
815 //
816 KeAttachProcess(&Process->Pcb);
817
818 //
819 // Allocate the TEB
820 //
821 Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
822 ASSERT(NT_SUCCESS(Status));
823
824 //
825 // Use SEH in case we can't load the TEB
826 //
827 _SEH2_TRY
828 {
829 //
830 // Initialize the PEB
831 //
832 RtlZeroMemory(Teb, sizeof(TEB));
833
834 //
835 // Set TIB Data
836 //
837 #ifdef _M_AMD64
838 Teb->NtTib.ExceptionList = NULL;
839 #else
840 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
841 #endif
842 Teb->NtTib.Self = (PNT_TIB)Teb;
843
844 //
845 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
846 //
847 Teb->NtTib.Version = 30 << 8;
848
849 //
850 // Set TEB Data
851 //
852 Teb->ClientId = *ClientId;
853 Teb->RealClientId = *ClientId;
854 Teb->ProcessEnvironmentBlock = Process->Peb;
855 Teb->CurrentLocale = PsDefaultThreadLocaleId;
856
857 //
858 // Check if we have a grandparent TEB
859 //
860 if ((InitialTeb->PreviousStackBase == NULL) &&
861 (InitialTeb->PreviousStackLimit == NULL))
862 {
863 //
864 // Use initial TEB values
865 //
866 Teb->NtTib.StackBase = InitialTeb->StackBase;
867 Teb->NtTib.StackLimit = InitialTeb->StackLimit;
868 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
869 }
870 else
871 {
872 //
873 // Use grandparent TEB values
874 //
875 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
876 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
877 }
878
879 //
880 // Initialize the static unicode string
881 //
882 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
883 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
884 }
885 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
886 {
887 //
888 // Get error code
889 //
890 Status = _SEH2_GetExceptionCode();
891 }
892 _SEH2_END;
893
894 //
895 // Return
896 //
897 KeDetachProcess();
898 *BaseTeb = Teb;
899 return Status;
900 }
901
902 VOID
903 NTAPI
904 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
905 {
906 PMMPFN Pfn1;
907 PMMPTE sysPte;
908 MMPTE tempPte;
909
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;
923
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;
928
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);
934 }
935
936 NTSTATUS
937 NTAPI
938 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
939 IN PEPROCESS ProcessClone OPTIONAL,
940 IN PVOID Section OPTIONAL,
941 IN OUT PULONG Flags,
942 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
943 {
944 NTSTATUS Status = STATUS_SUCCESS;
945 SIZE_T ViewSize = 0;
946 PVOID ImageBase = 0;
947 PROS_SECTION_OBJECT SectionObject = Section;
948 PMMPTE PointerPte;
949 KIRQL OldIrql;
950 PMMPDE PointerPde;
951 PFN_NUMBER PageFrameNumber;
952 UNICODE_STRING FileName;
953 PWCHAR Source;
954 PCHAR Destination;
955 USHORT Length = 0;
956 MMPTE TempPte;
957
958 /* We should have a PDE */
959 ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
960 ASSERT(Process->PdeUpdateNeeded == FALSE);
961
962 /* Attach to the process */
963 KeAttachProcess(&Process->Pcb);
964
965 /* The address space should now been in phase 1 or 0 */
966 ASSERT(Process->AddressSpaceInitialized <= 1);
967 Process->AddressSpaceInitialized = 2;
968
969 /* Initialize the Addresss Space lock */
970 KeInitializeGuardedMutex(&Process->AddressCreationLock);
971 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
972
973 /* Initialize AVL tree */
974 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
975 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
976
977 /* Lock PFN database */
978 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
979
980 /* Setup the PFN for the PDE base of this process */
981 #ifdef _M_AMD64
982 PointerPte = MiAddressToPte(PXE_BASE);
983 #else
984 PointerPte = MiAddressToPte(PDE_BASE);
985 #endif
986 PageFrameNumber = PFN_FROM_PTE(PointerPte);
987 ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE);
988 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
989
990 /* Do the same for hyperspace */
991 #ifdef _M_AMD64
992 PointerPde = MiAddressToPxe((PVOID)HYPER_SPACE);
993 #else
994 PointerPde = MiAddressToPde(HYPER_SPACE);
995 #endif
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);
999
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);
1009
1010 /* Now initialize the working set list */
1011 MiInitializeWorkingSetList(Process);
1012
1013 /* Sanity check */
1014 ASSERT(Process->PhysicalVadRoot == NULL);
1015
1016 /* Release PFN lock */
1017 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1018
1019 /* Lock the VAD, ARM3-owned ranges away */
1020 MiRosTakeOverSharedUserPage(Process);
1021
1022 /* Check if there's a Section Object */
1023 if (SectionObject)
1024 {
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)
1029 {
1030 /* Loop the file name*/
1031 while (Source > FileName.Buffer)
1032 {
1033 /* Make sure this isn't a backslash */
1034 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
1035 {
1036 /* If so, stop it here */
1037 Source++;
1038 break;
1039 }
1040 else
1041 {
1042 /* Otherwise, keep going */
1043 Length++;
1044 }
1045 }
1046 }
1047
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;
1053
1054 /* Check if caller wants an audit name */
1055 if (AuditName)
1056 {
1057 /* Setup the audit name */
1058 Status = SeInitializeProcessAuditName(SectionObject->FileObject,
1059 FALSE,
1060 AuditName);
1061 if (!NT_SUCCESS(Status))
1062 {
1063 /* Fail */
1064 KeDetachProcess();
1065 return Status;
1066 }
1067 }
1068
1069 /* Map the section */
1070 Status = MmMapViewOfSection(Section,
1071 Process,
1072 (PVOID*)&ImageBase,
1073 0,
1074 0,
1075 NULL,
1076 &ViewSize,
1077 0,
1078 MEM_COMMIT,
1079 PAGE_READWRITE);
1080
1081 /* Save the pointer */
1082 Process->SectionBaseAddress = ImageBase;
1083 }
1084
1085 /* Be nice and detach */
1086 KeDetachProcess();
1087
1088 /* Return status to caller */
1089 return Status;
1090 }
1091
1092 NTSTATUS
1093 NTAPI
1094 INIT_FUNCTION
1095 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
1096 IN PULONG_PTR DirectoryTableBase)
1097 {
1098 /* Share the directory base with the idle process */
1099 DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
1100 DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
1101
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;
1108
1109 /* Done */
1110 Process->HasAddressSpace = TRUE;//??
1111 return STATUS_SUCCESS;
1112 }
1113
1114 NTSTATUS
1115 NTAPI
1116 INIT_FUNCTION
1117 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
1118 {
1119 /* Lock the VAD, ARM3-owned ranges away */
1120 MiRosTakeOverSharedUserPage(Process);
1121 return STATUS_SUCCESS;
1122 }
1123
1124 #ifdef _M_IX86
1125 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1126 BOOLEAN
1127 NTAPI
1128 MmCreateProcessAddressSpace(IN ULONG MinWs,
1129 IN PEPROCESS Process,
1130 OUT PULONG_PTR DirectoryTableBase)
1131 {
1132 KIRQL OldIrql;
1133 PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
1134 PMMPTE PointerPte;
1135 MMPTE TempPte, PdePte;
1136 ULONG PdeOffset;
1137 PMMPTE SystemTable, HyperTable;
1138 ULONG Color;
1139 PMMPFN Pfn1;
1140
1141 /* Choose a process color */
1142 Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
1143
1144 /* Setup the hyperspace lock */
1145 KeInitializeSpinLock(&Process->HyperSpaceLock);
1146
1147 /* Lock PFN database */
1148 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1149
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);
1154 if (!PdeIndex)
1155 {
1156 /* No zero pages, grab a free one */
1157 PdeIndex = MiRemoveAnyPage(Color);
1158
1159 /* Zero it outside the PFN lock */
1160 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1161 MiZeroPhysicalPage(PdeIndex);
1162 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1163 }
1164
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);
1169 if (!HyperIndex)
1170 {
1171 /* No zero pages, grab a free one */
1172 HyperIndex = MiRemoveAnyPage(Color);
1173
1174 /* Zero it outside the PFN lock */
1175 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1176 MiZeroPhysicalPage(HyperIndex);
1177 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1178 }
1179
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);
1184 if (!WsListIndex)
1185 {
1186 /* No zero pages, grab a free one */
1187 WsListIndex = MiRemoveAnyPage(Color);
1188
1189 /* Zero it outside the PFN lock */
1190 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1191 MiZeroPhysicalPage(WsListIndex);
1192 }
1193 else
1194 {
1195 /* Release the PFN lock */
1196 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1197 }
1198
1199 /* Switch to phase 1 initialization */
1200 ASSERT(Process->AddressSpaceInitialized == 0);
1201 Process->AddressSpaceInitialized = 1;
1202
1203 /* Set the base directory pointers */
1204 Process->WorkingSetPage = WsListIndex;
1205 DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
1206 DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
1207
1208 /* Make sure we don't already have a page directory setup */
1209 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
1210
1211 /* Get a PTE to map hyperspace */
1212 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1213 ASSERT(PointerPte != NULL);
1214
1215 /* Build it */
1216 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1217 PointerPte,
1218 MM_READWRITE,
1219 HyperIndex);
1220
1221 /* Set it dirty and map it */
1222 MI_MAKE_DIRTY_PAGE(&PdePte);
1223 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1224
1225 /* Now get hyperspace's page table */
1226 HyperTable = MiPteToAddress(PointerPte);
1227
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;
1235
1236 /* Let go of the system PTE */
1237 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1238
1239 /* Save the PTE address of the page directory itself */
1240 Pfn1 = MiGetPfnEntry(PdeIndex);
1241 Pfn1->PteAddress = (PMMPTE)PDE_BASE;
1242
1243 /* Insert us into the Mm process list */
1244 InsertTailList(&MmProcessList, &Process->MmProcessLinks);
1245
1246 /* Get a PTE to map the page directory */
1247 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1248 ASSERT(PointerPte != NULL);
1249
1250 /* Build it */
1251 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1252 PointerPte,
1253 MM_READWRITE,
1254 PdeIndex);
1255
1256 /* Set it dirty and map it */
1257 MI_MAKE_DIRTY_PAGE(&PdePte);
1258 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1259
1260 /* Now get the page directory (which we'll double map, so call it a page table */
1261 SystemTable = MiPteToAddress(PointerPte);
1262
1263 /* Copy all the kernel mappings */
1264 PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
1265 RtlCopyMemory(&SystemTable[PdeOffset],
1266 MiAddressToPde(MmSystemRangeStart),
1267 PAGE_SIZE - PdeOffset * sizeof(MMPTE));
1268
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;
1274
1275 /* Sanity check */
1276 PdeOffset++;
1277 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
1278
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;
1283
1284 /* Let go of the system PTE */
1285 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1286 return TRUE;
1287 }
1288 #endif
1289
1290 VOID
1291 NTAPI
1292 MmCleanProcessAddressSpace(IN PEPROCESS Process)
1293 {
1294 PMMVAD Vad;
1295 PMM_AVL_TABLE VadTree;
1296 PETHREAD Thread = PsGetCurrentThread();
1297
1298 /* Only support this */
1299 ASSERT(Process->AddressSpaceInitialized == 2);
1300
1301 /* Lock the process address space from changes */
1302 MmLockAddressSpace(&Process->Vm);
1303
1304 /* VM is deleted now */
1305 Process->VmDeleted = TRUE;
1306
1307 /* Enumerate the VADs */
1308 VadTree = &Process->VadRoot;
1309 while (VadTree->NumberGenericTableElements)
1310 {
1311 /* Grab the current VAD */
1312 Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
1313
1314 /* Lock the working set */
1315 MiLockProcessWorkingSet(Process, Thread);
1316
1317 /* Remove this VAD from the tree */
1318 ASSERT(VadTree->NumberGenericTableElements >= 1);
1319 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
1320
1321 /* Only regular VADs supported for now */
1322 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1323
1324 /* Check if this is a section VAD */
1325 if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
1326 {
1327 /* Remove the view */
1328 MiRemoveMappedView(Process, Vad);
1329 }
1330 else
1331 {
1332 /* Delete the addresses */
1333 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
1334 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
1335 Vad);
1336
1337 /* Release the working set */
1338 MiUnlockProcessWorkingSet(Process, Thread);
1339 }
1340
1341 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1342 if (Vad->u.VadFlags.Spare == 1)
1343 {
1344 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1345 Vad->u.VadFlags.Spare = 2;
1346 continue;
1347 }
1348
1349 /* Free the VAD memory */
1350 ExFreePool(Vad);
1351 }
1352
1353 /* Release the address space */
1354 MmUnlockAddressSpace(&Process->Vm);
1355 }
1356
1357 VOID
1358 NTAPI
1359 MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
1360 {
1361 PMMPFN Pfn1, Pfn2;
1362 KIRQL OldIrql;
1363 PFN_NUMBER PageFrameIndex;
1364
1365 //ASSERT(Process->CommitCharge == 0);
1366
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");
1373 KeDetachProcess();
1374
1375 /* Acquire the PFN lock */
1376 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1377
1378 /* Check for fully initialized process */
1379 if (Process->AddressSpaceInitialized == 2)
1380 {
1381 /* Map the working set page and its page table */
1382 Pfn1 = MiGetPfnEntry(Process->WorkingSetPage);
1383 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
1384
1385 /* Nuke it */
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);
1391
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);
1396
1397 /* Nuke it */
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));
1402
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);
1409
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);
1415 }
1416 else
1417 {
1418 /* A partly-initialized process should never exit through here */
1419 ASSERT(FALSE);
1420 }
1421
1422 /* Release the PFN lock */
1423 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1424
1425 /* No support for sessions yet */
1426 ASSERT(Process->Session == 0);
1427
1428 /* Clear out the PDE pages */
1429 Process->Pcb.DirectoryTableBase[0] = 0;
1430 Process->Pcb.DirectoryTableBase[1] = 0;
1431 }
1432
1433 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
1434
1435 KGUARDED_MUTEX MiSessionIdMutex;
1436 PRTL_BITMAP MiSessionIdBitmap;
1437 volatile LONG MiSessionLeaderExists;
1438
1439 VOID
1440 NTAPI
1441 MiInitializeSessionIds(VOID)
1442 {
1443 /* FIXME: Other stuff should go here */
1444
1445 /* Initialize the lock */
1446 KeInitializeGuardedMutex(&MiSessionIdMutex);
1447
1448 /* Allocate the bitmap */
1449 MiSessionIdBitmap = ExAllocatePoolWithTag(PagedPool,
1450 sizeof(RTL_BITMAP) + ((64 + 31) / 32) * 4,
1451 ' mM');
1452 if (MiSessionIdBitmap)
1453 {
1454 /* Free all the bits */
1455 RtlInitializeBitMap(MiSessionIdBitmap, (PVOID)(MiSessionIdBitmap + 1), 64);
1456 RtlClearAllBits(MiSessionIdBitmap);
1457 }
1458 else
1459 {
1460 /* Die if we couldn't allocate the bitmap */
1461 KeBugCheckEx(INSTALL_MORE_MEMORY,
1462 MmNumberOfPhysicalPages,
1463 MmLowestPhysicalPage,
1464 MmHighestPhysicalPage,
1465 0x200);
1466 }
1467 }
1468
1469 VOID
1470 NTAPI
1471 MiSessionLeader(IN PEPROCESS Process)
1472 {
1473 KIRQL OldIrql;
1474
1475 /* Set the flag while under the expansion lock */
1476 OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
1477 Process->Vm.Flags.SessionLeader = TRUE;
1478 KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
1479 }
1480
1481 NTSTATUS
1482 NTAPI
1483 MiSessionCreateInternal(OUT PULONG SessionId)
1484 {
1485 PEPROCESS Process = PsGetCurrentProcess();
1486 ULONG NewFlags, Flags;
1487
1488 /* Loop so we can set the session-is-creating flag */
1489 Flags = Process->Flags;
1490 while (TRUE)
1491 {
1492 /* Check if it's already set */
1493 if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
1494 {
1495 /* Bail out */
1496 DPRINT1("Lost session race\n");
1497 return STATUS_ALREADY_COMMITTED;
1498 }
1499
1500 /* Now try to set it */
1501 NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
1502 Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
1503 Flags);
1504 if (NewFlags == Flags) break;
1505
1506 /* It changed, try again */
1507 Flags = NewFlags;
1508 }
1509
1510 /* Now we should own the flag */
1511 ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
1512
1513 /* Allocate a new Session ID */
1514 KeAcquireGuardedMutex(&MiSessionIdMutex);
1515 *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
1516 if (*SessionId == 0xFFFFFFFF)
1517 {
1518 DPRINT1("Too many sessions created. Expansion not yet supported\n");
1519 return STATUS_NO_MEMORY;
1520 }
1521 KeReleaseGuardedMutex(&MiSessionIdMutex);
1522
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;
1527 }
1528
1529 NTSTATUS
1530 NTAPI
1531 MmSessionCreate(OUT PULONG SessionId)
1532 {
1533 PEPROCESS Process = PsGetCurrentProcess();
1534 ULONG SessionLeaderExists;
1535 NTSTATUS Status;
1536
1537 /* Fail if the process is already in a session */
1538 if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
1539 {
1540 DPRINT1("Process already in session\n");
1541 return STATUS_ALREADY_COMMITTED;
1542 }
1543
1544 /* Check if the process is already the session leader */
1545 if (!Process->Vm.Flags.SessionLeader)
1546 {
1547 /* Atomically set it as the leader */
1548 SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
1549 if (SessionLeaderExists)
1550 {
1551 DPRINT1("Session leader race\n");
1552 return STATUS_INVALID_SYSTEM_SERVICE;
1553 }
1554
1555 /* Do the work required to upgrade him */
1556 MiSessionLeader(Process);
1557 }
1558
1559 /* FIXME: Actually create a session */
1560 KeEnterCriticalRegion();
1561 Status = MiSessionCreateInternal(SessionId);
1562 KeLeaveCriticalRegion();
1563
1564 /* Set and assert the flags, and return */
1565 PspSetProcessFlag(Process, PSF_PROCESS_IN_SESSION_BIT);
1566 ASSERT(MiSessionLeaderExists == 1);
1567 return Status;
1568 }
1569
1570 NTSTATUS
1571 NTAPI
1572 MmSessionDelete(IN ULONG SessionId)
1573 {
1574 PEPROCESS Process = PsGetCurrentProcess();
1575
1576 /* Process must be in a session */
1577 if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
1578 {
1579 DPRINT1("Not in a session!\n");
1580 return STATUS_UNABLE_TO_FREE_VM;
1581 }
1582
1583 /* It must be the session leader */
1584 if (!Process->Vm.Flags.SessionLeader)
1585 {
1586 DPRINT1("Not a session leader!\n");
1587 return STATUS_UNABLE_TO_FREE_VM;
1588 }
1589
1590 /* Remove one reference count */
1591 KeEnterCriticalRegion();
1592 /* FIXME: Do it */
1593 KeLeaveCriticalRegion();
1594
1595 /* All done */
1596 return STATUS_SUCCESS;
1597 }
1598
1599 /* SYSTEM CALLS ***************************************************************/
1600
1601 NTSTATUS
1602 NTAPI
1603 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
1604 IN OUT PULONG_PTR NumberOfPages,
1605 IN OUT PULONG_PTR UserPfnArray)
1606 {
1607 UNIMPLEMENTED;
1608 return STATUS_NOT_IMPLEMENTED;
1609 }
1610
1611 NTSTATUS
1612 NTAPI
1613 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
1614 IN ULONG_PTR NumberOfPages,
1615 IN OUT PULONG_PTR UserPfnArray)
1616 {
1617 UNIMPLEMENTED;
1618 return STATUS_NOT_IMPLEMENTED;
1619 }
1620
1621 NTSTATUS
1622 NTAPI
1623 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
1624 IN ULONG_PTR NumberOfPages,
1625 IN OUT PULONG_PTR UserPfnArray)
1626 {
1627 UNIMPLEMENTED;
1628 return STATUS_NOT_IMPLEMENTED;
1629 }
1630
1631 NTSTATUS
1632 NTAPI
1633 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
1634 IN OUT PULONG_PTR NumberOfPages,
1635 IN OUT PULONG_PTR UserPfnArray)
1636 {
1637 UNIMPLEMENTED;
1638 return STATUS_NOT_IMPLEMENTED;
1639 }
1640
1641 /* EOF */