xref: /reactos/ntoskrnl/mm/ARM3/procsup.c (revision 647b518b)
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 <mm/ARM3/miarm.h>
17 
18 /* GLOBALS ********************************************************************/
19 
20 ULONG MmProcessColorSeed = 0x12345678;
21 ULONG MmMaximumDeadKernelStacks = 5;
22 SLIST_HEADER MmDeadStackSListHead;
23 ULONG MmRotatingUniprocessorNumber = 0;
24 
25 /* PRIVATE FUNCTIONS **********************************************************/
26 
27 NTSTATUS
28 NTAPI
MiCreatePebOrTeb(IN PEPROCESS Process,IN ULONG Size,OUT PULONG_PTR BaseAddress)29 MiCreatePebOrTeb(IN PEPROCESS Process,
30                  IN ULONG Size,
31                  OUT PULONG_PTR BaseAddress)
32 {
33     PMMVAD_LONG Vad;
34     NTSTATUS Status;
35     ULONG_PTR HighestAddress, RandomBase;
36     ULONG AlignedSize;
37     LARGE_INTEGER CurrentTime;
38 
39     Status = PsChargeProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
40     if (!NT_SUCCESS(Status))
41         return Status;
42 
43     /* Allocate a VAD */
44     Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
45     if (!Vad)
46     {
47         Status = STATUS_NO_MEMORY;
48         goto FailPath;
49     }
50 
51     /* Setup the primary flags with the size, and make it commited, private, RW */
52     Vad->u.LongFlags = 0;
53     Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
54     Vad->u.VadFlags.MemCommit = TRUE;
55     Vad->u.VadFlags.PrivateMemory = TRUE;
56     Vad->u.VadFlags.Protection = MM_READWRITE;
57     Vad->u.VadFlags.NoChange = TRUE;
58     Vad->u1.Parent = NULL;
59 
60     /* Setup the secondary flags to make it a secured, writable, long VAD */
61     Vad->u2.LongFlags2 = 0;
62     Vad->u2.VadFlags2.OneSecured = TRUE;
63     Vad->u2.VadFlags2.LongVad = TRUE;
64     Vad->u2.VadFlags2.ReadOnly = FALSE;
65 
66     Vad->ControlArea = NULL; // For Memory-Area hack
67     Vad->FirstPrototypePte = NULL;
68 
69     /* Check if this is a PEB creation */
70     ASSERT(sizeof(TEB) != sizeof(PEB));
71     if (Size == sizeof(PEB))
72     {
73         /* Create a random value to select one page in a 64k region */
74         KeQueryTickCount(&CurrentTime);
75         CurrentTime.LowPart &= (_64K / PAGE_SIZE) - 1;
76 
77         /* Calculate a random base address */
78         RandomBase = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
79         RandomBase -= CurrentTime.LowPart << PAGE_SHIFT;
80 
81         /* Make sure the base address is not too high */
82         AlignedSize = ROUND_TO_PAGES(Size);
83         if ((RandomBase + AlignedSize) > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1)
84         {
85             RandomBase = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1 - AlignedSize;
86         }
87 
88         /* Calculate the highest allowed address */
89         HighestAddress = RandomBase + AlignedSize - 1;
90     }
91     else
92     {
93         HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
94     }
95 
96     *BaseAddress = 0;
97     Status = MiInsertVadEx((PMMVAD)Vad,
98                            BaseAddress,
99                            Size,
100                            HighestAddress,
101                            PAGE_SIZE,
102                            MEM_TOP_DOWN);
103     if (!NT_SUCCESS(Status))
104     {
105         ExFreePoolWithTag(Vad, 'ldaV');
106         Status = STATUS_NO_MEMORY;
107         goto FailPath;
108     }
109 
110 
111     /* Success */
112     return STATUS_SUCCESS;
113 
114 FailPath:
115     PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
116 
117     return Status;
118 }
119 
120 VOID
121 NTAPI
MmDeleteTeb(IN PEPROCESS Process,IN PTEB Teb)122 MmDeleteTeb(IN PEPROCESS Process,
123             IN PTEB Teb)
124 {
125     ULONG_PTR TebEnd;
126     PETHREAD Thread = PsGetCurrentThread();
127     PMMVAD Vad;
128     PMM_AVL_TABLE VadTree = &Process->VadRoot;
129     DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
130 
131     /* TEB is one page */
132     TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
133 
134     /* Attach to the process */
135     KeAttachProcess(&Process->Pcb);
136 
137     /* Lock the process address space */
138     KeAcquireGuardedMutex(&Process->AddressCreationLock);
139 
140     /* Find the VAD, make sure it's a TEB VAD */
141     Vad = MiLocateAddress(Teb);
142     DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
143     ASSERT(Vad != NULL);
144     if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
145     {
146         /* Bug in the AVL code? */
147         DPRINT1("Corrupted VAD!\n");
148     }
149     else
150     {
151         /* Sanity checks for a valid TEB VAD */
152         ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
153                (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
154         ASSERT(Vad->u.VadFlags.NoChange == TRUE);
155         ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE);
156         ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
157 
158         /* Lock the working set */
159         MiLockProcessWorkingSetUnsafe(Process, Thread);
160 
161         /* Remove this VAD from the tree */
162         ASSERT(VadTree->NumberGenericTableElements >= 1);
163         MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
164 
165         /* Delete the pages */
166         MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL);
167 
168         /* Release the working set */
169         MiUnlockProcessWorkingSetUnsafe(Process, Thread);
170 
171         /* Remove the VAD */
172         ExFreePool(Vad);
173 
174         /* Return the quota the VAD used */
175         PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
176     }
177 
178     /* Release the address space lock */
179     KeReleaseGuardedMutex(&Process->AddressCreationLock);
180 
181     /* Detach */
182     KeDetachProcess();
183 }
184 
185 VOID
186 NTAPI
MmDeleteKernelStack(IN PVOID StackBase,IN BOOLEAN GuiStack)187 MmDeleteKernelStack(IN PVOID StackBase,
188                     IN BOOLEAN GuiStack)
189 {
190     PMMPTE PointerPte;
191     PFN_NUMBER PageFrameNumber, PageTableFrameNumber;
192     PFN_COUNT StackPages;
193     PMMPFN Pfn1, Pfn2;
194     ULONG i;
195     KIRQL OldIrql;
196     PSLIST_ENTRY SListEntry;
197 
198     //
199     // This should be the guard page, so decrement by one
200     //
201     PointerPte = MiAddressToPte(StackBase);
202     PointerPte--;
203 
204     //
205     // If this is a small stack, just push the stack onto the dead stack S-LIST
206     //
207     if (!GuiStack)
208     {
209         if (ExQueryDepthSList(&MmDeadStackSListHead) < MmMaximumDeadKernelStacks)
210         {
211             SListEntry = ((PSLIST_ENTRY)StackBase) - 1;
212             InterlockedPushEntrySList(&MmDeadStackSListHead, SListEntry);
213             return;
214         }
215     }
216 
217     //
218     // Calculate pages used
219     //
220     StackPages = BYTES_TO_PAGES(GuiStack ?
221                                 MmLargeStackSize : KERNEL_STACK_SIZE);
222 
223     /* Acquire the PFN lock */
224     OldIrql = MiAcquirePfnLock();
225 
226     //
227     // Loop them
228     //
229     for (i = 0; i < StackPages; i++)
230     {
231         //
232         // Check if this is a valid PTE
233         //
234         if (PointerPte->u.Hard.Valid == 1)
235         {
236             /* Get the PTE's page */
237             PageFrameNumber = PFN_FROM_PTE(PointerPte);
238             Pfn1 = MiGetPfnEntry(PageFrameNumber);
239 
240             /* Now get the page of the page table mapping it */
241             PageTableFrameNumber = Pfn1->u4.PteFrame;
242             Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
243 
244             /* Remove a shared reference, since the page is going away */
245             MiDecrementShareCount(Pfn2, PageTableFrameNumber);
246 
247             /* Set the special pending delete marker */
248             MI_SET_PFN_DELETED(Pfn1);
249 
250             /* And now delete the actual stack page */
251             MiDecrementShareCount(Pfn1, PageFrameNumber);
252         }
253 
254         //
255         // Next one
256         //
257         PointerPte--;
258     }
259 
260     //
261     // We should be at the guard page now
262     //
263     ASSERT(PointerPte->u.Hard.Valid == 0);
264 
265     /* Release the PFN lock */
266     MiReleasePfnLock(OldIrql);
267 
268     //
269     // Release the PTEs
270     //
271     MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace);
272 }
273 
274 PVOID
275 NTAPI
MmCreateKernelStack(IN BOOLEAN GuiStack,IN UCHAR Node)276 MmCreateKernelStack(IN BOOLEAN GuiStack,
277                     IN UCHAR Node)
278 {
279     PFN_COUNT StackPtes, StackPages;
280     PMMPTE PointerPte, StackPte;
281     PVOID BaseAddress;
282     MMPTE TempPte, InvalidPte;
283     KIRQL OldIrql;
284     PFN_NUMBER PageFrameIndex;
285     ULONG i;
286     PSLIST_ENTRY SListEntry;
287 
288     //
289     // Calculate pages needed
290     //
291     if (GuiStack)
292     {
293         //
294         // We'll allocate 64KB stack, but only commit 12K
295         //
296         StackPtes = BYTES_TO_PAGES(MmLargeStackSize);
297         StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT);
298     }
299     else
300     {
301         //
302         // If the dead stack S-LIST has a stack on it, use it instead of allocating
303         // new system PTEs for this stack
304         //
305         if (ExQueryDepthSList(&MmDeadStackSListHead))
306         {
307             SListEntry = InterlockedPopEntrySList(&MmDeadStackSListHead);
308             if (SListEntry != NULL)
309             {
310                 BaseAddress = (SListEntry + 1);
311                 return BaseAddress;
312             }
313         }
314 
315         //
316         // We'll allocate 12K and that's it
317         //
318         StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE);
319         StackPages = StackPtes;
320     }
321 
322     //
323     // Reserve stack pages, plus a guard page
324     //
325     StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace);
326     if (!StackPte) return NULL;
327 
328     //
329     // Get the stack address
330     //
331     BaseAddress = MiPteToAddress(StackPte + StackPtes + 1);
332 
333     //
334     // Select the right PTE address where we actually start committing pages
335     //
336     PointerPte = StackPte;
337     if (GuiStack) PointerPte += BYTES_TO_PAGES(MmLargeStackSize -
338                                                KERNEL_LARGE_STACK_COMMIT);
339 
340 
341     /* Setup the temporary invalid PTE */
342     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
343 
344     /* Setup the template stack PTE */
345     MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
346 
347     //
348     // Acquire the PFN DB lock
349     //
350     OldIrql = MiAcquirePfnLock();
351 
352     //
353     // Loop each stack page
354     //
355     for (i = 0; i < StackPages; i++)
356     {
357         //
358         // Next PTE
359         //
360         PointerPte++;
361 
362         /* Get a page and write the current invalid PTE */
363         MI_SET_USAGE(MI_USAGE_KERNEL_STACK);
364         MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
365         PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
366         MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
367 
368         /* Initialize the PFN entry for this page */
369         MiInitializePfn(PageFrameIndex, PointerPte, 1);
370 
371         /* Write the valid PTE */
372         TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
373         MI_WRITE_VALID_PTE(PointerPte, TempPte);
374     }
375 
376     //
377     // Release the PFN lock
378     //
379     MiReleasePfnLock(OldIrql);
380 
381     //
382     // Return the stack address
383     //
384     return BaseAddress;
385 }
386 
387 NTSTATUS
388 NTAPI
MmGrowKernelStackEx(IN PVOID StackPointer,IN ULONG GrowSize)389 MmGrowKernelStackEx(IN PVOID StackPointer,
390                     IN ULONG GrowSize)
391 {
392     PKTHREAD Thread = KeGetCurrentThread();
393     PMMPTE LimitPte, NewLimitPte, LastPte;
394     KIRQL OldIrql;
395     MMPTE TempPte, InvalidPte;
396     PFN_NUMBER PageFrameIndex;
397 
398     //
399     // Make sure the stack did not overflow
400     //
401     ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
402            (MmLargeStackSize + PAGE_SIZE));
403 
404     //
405     // Get the current stack limit
406     //
407     LimitPte = MiAddressToPte(Thread->StackLimit);
408     ASSERT(LimitPte->u.Hard.Valid == 1);
409 
410     //
411     // Get the new one and make sure this isn't a retarded request
412     //
413     NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
414     if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
415 
416     //
417     // Now make sure you're not going past the reserved space
418     //
419     LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
420                                      MmLargeStackSize));
421     if (NewLimitPte < LastPte)
422     {
423         //
424         // Sorry!
425         //
426         return STATUS_STACK_OVERFLOW;
427     }
428 
429     //
430     // Calculate the number of new pages
431     //
432     LimitPte--;
433 
434     /* Setup the temporary invalid PTE */
435     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
436 
437     //
438     // Acquire the PFN DB lock
439     //
440     OldIrql = MiAcquirePfnLock();
441 
442     //
443     // Loop each stack page
444     //
445     while (LimitPte >= NewLimitPte)
446     {
447         /* Get a page and write the current invalid PTE */
448         MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION);
449         MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
450         PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
451         MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
452 
453         /* Initialize the PFN entry for this page */
454         MiInitializePfn(PageFrameIndex, LimitPte, 1);
455 
456         /* Setup the template stack PTE */
457         MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
458 
459         /* Write the valid PTE */
460         MI_WRITE_VALID_PTE(LimitPte--, TempPte);
461     }
462 
463     //
464     // Release the PFN lock
465     //
466     MiReleasePfnLock(OldIrql);
467 
468     //
469     // Set the new limit
470     //
471     Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
472     return STATUS_SUCCESS;
473 }
474 
475 NTSTATUS
476 NTAPI
MmGrowKernelStack(IN PVOID StackPointer)477 MmGrowKernelStack(IN PVOID StackPointer)
478 {
479     //
480     // Call the extended version
481     //
482     return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
483 }
484 
485 NTSTATUS
486 NTAPI
MmSetMemoryPriorityProcess(IN PEPROCESS Process,IN UCHAR MemoryPriority)487 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
488                            IN UCHAR MemoryPriority)
489 {
490     UCHAR OldPriority;
491 
492     //
493     // Check if we have less then 16MB of Physical Memory
494     //
495     if ((MmSystemSize == MmSmallSystem) &&
496         (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
497     {
498         //
499         // Always use background priority
500         //
501         MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
502     }
503 
504     //
505     // Save the old priority and update it
506     //
507     OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
508     Process->Vm.Flags.MemoryPriority = MemoryPriority;
509 
510     //
511     // Return the old priority
512     //
513     return OldPriority;
514 }
515 
516 NTSTATUS
517 NTAPI
MmCreatePeb(IN PEPROCESS Process,IN PINITIAL_PEB InitialPeb,OUT PPEB * BasePeb)518 MmCreatePeb(IN PEPROCESS Process,
519             IN PINITIAL_PEB InitialPeb,
520             OUT PPEB *BasePeb)
521 {
522     PPEB Peb = NULL;
523     LARGE_INTEGER SectionOffset;
524     SIZE_T ViewSize = 0;
525     PVOID TableBase = NULL;
526     PIMAGE_NT_HEADERS NtHeaders;
527     PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
528     NTSTATUS Status;
529     USHORT Characteristics;
530     SectionOffset.QuadPart = (ULONGLONG)0;
531     *BasePeb = NULL;
532 
533     //
534     // Attach to Process
535     //
536     KeAttachProcess(&Process->Pcb);
537 
538     //
539     // Map NLS Tables
540     //
541     Status = MmMapViewOfSection(ExpNlsSectionPointer,
542                                 (PEPROCESS)Process,
543                                 &TableBase,
544                                 0,
545                                 0,
546                                 &SectionOffset,
547                                 &ViewSize,
548                                 ViewShare,
549                                 MEM_TOP_DOWN,
550                                 PAGE_READONLY);
551     DPRINT("NLS Tables at: %p\n", TableBase);
552     if (!NT_SUCCESS(Status))
553     {
554         /* Cleanup and exit */
555         KeDetachProcess();
556         return Status;
557     }
558 
559     //
560     // Allocate the PEB
561     //
562     Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
563     DPRINT("PEB at: %p\n", Peb);
564     if (!NT_SUCCESS(Status))
565     {
566         /* Cleanup and exit */
567         KeDetachProcess();
568         return Status;
569     }
570 
571     //
572     // Use SEH in case we can't load the PEB
573     //
574     _SEH2_TRY
575     {
576         //
577         // Initialize the PEB
578         //
579         RtlZeroMemory(Peb, sizeof(PEB));
580 
581         //
582         // Set up data
583         //
584         Peb->ImageBaseAddress = Process->SectionBaseAddress;
585         Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
586         Peb->Mutant = InitialPeb->Mutant;
587         Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
588 
589         //
590         // NLS
591         //
592         Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
593         Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
594         Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
595 
596         //
597         // Default Version Data (could get changed below)
598         //
599         Peb->OSMajorVersion = NtMajorVersion;
600         Peb->OSMinorVersion = NtMinorVersion;
601         Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
602         Peb->OSPlatformId = VER_PLATFORM_WIN32_NT;
603         Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
604 
605         //
606         // Heap and Debug Data
607         //
608         Peb->NumberOfProcessors = KeNumberProcessors;
609         Peb->ImageProcessAffinityMask = KeActiveProcessors;
610         Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL);
611         Peb->NtGlobalFlag = NtGlobalFlag;
612         Peb->HeapSegmentReserve = MmHeapSegmentReserve;
613         Peb->HeapSegmentCommit = MmHeapSegmentCommit;
614         Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
615         Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
616         Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
617         Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
618         Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
619         Peb->ProcessHeaps = (PVOID*)(Peb + 1);
620 
621         //
622         // Session ID
623         //
624         if (Process->Session) Peb->SessionId = MmGetSessionId(Process);
625     }
626     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
627     {
628         //
629         // Fail
630         //
631         KeDetachProcess();
632         _SEH2_YIELD(return _SEH2_GetExceptionCode());
633     }
634     _SEH2_END;
635 
636     //
637     // Use SEH in case we can't load the image
638     //
639     _SEH2_TRY
640     {
641         //
642         // Get NT Headers
643         //
644         NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
645         Characteristics = NtHeaders->FileHeader.Characteristics;
646     }
647     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
648     {
649         //
650         // Fail
651         //
652         KeDetachProcess();
653         _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
654     }
655     _SEH2_END;
656 
657     //
658     // Parse the headers
659     //
660     if (NtHeaders)
661     {
662         //
663         // Use SEH in case we can't load the headers
664         //
665         _SEH2_TRY
666         {
667             //
668             // Get the Image Config Data too
669             //
670             ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
671                                                            TRUE,
672                                                            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
673                                                            (PULONG)&ViewSize);
674             if (ImageConfigData)
675             {
676                 //
677                 // Probe it
678                 //
679                 ProbeForRead(ImageConfigData,
680                              sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
681                              sizeof(ULONG));
682             }
683 
684             //
685             // Write subsystem data
686             //
687             Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
688             Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
689             Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
690 
691             //
692             // Check for version data
693             //
694             if (NtHeaders->OptionalHeader.Win32VersionValue)
695             {
696                 //
697                 // Extract values and write them
698                 //
699                 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
700                 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
701                 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
702                 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
703 
704                 /* Process CSD version override */
705                 if ((ImageConfigData) && (ImageConfigData->CSDVersion))
706                 {
707                     /* Take the value from the image configuration directory */
708                     Peb->OSCSDVersion = ImageConfigData->CSDVersion;
709                 }
710             }
711 
712             /* Process optional process affinity mask override */
713             if ((ImageConfigData) && (ImageConfigData->ProcessAffinityMask))
714             {
715                 /* Take the value from the image configuration directory */
716                 Peb->ImageProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
717             }
718 
719             //
720             // Check if this is a UP image
721             if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
722             {
723                 //
724                 // Set single processor rotating affinity.
725                 // See https://www.microsoftpressstore.com/articles/article.aspx?p=2233328&seqNum=3
726                 //
727                 Peb->ImageProcessAffinityMask = AFFINITY_MASK(MmRotatingUniprocessorNumber);
728                 ASSERT(Peb->ImageProcessAffinityMask & KeActiveProcessors);
729                 MmRotatingUniprocessorNumber = (MmRotatingUniprocessorNumber + 1) % KeNumberProcessors;
730             }
731         }
732         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
733         {
734             //
735             // Fail
736             //
737             KeDetachProcess();
738             _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
739         }
740         _SEH2_END;
741     }
742 
743     //
744     // Detach from the Process
745     //
746     KeDetachProcess();
747     *BasePeb = Peb;
748     return STATUS_SUCCESS;
749 }
750 
751 NTSTATUS
752 NTAPI
MmCreateTeb(IN PEPROCESS Process,IN PCLIENT_ID ClientId,IN PINITIAL_TEB InitialTeb,OUT PTEB * BaseTeb)753 MmCreateTeb(IN PEPROCESS Process,
754             IN PCLIENT_ID ClientId,
755             IN PINITIAL_TEB InitialTeb,
756             OUT PTEB *BaseTeb)
757 {
758     PTEB Teb;
759     NTSTATUS Status = STATUS_SUCCESS;
760     *BaseTeb = NULL;
761 
762     //
763     // Attach to Target
764     //
765     KeAttachProcess(&Process->Pcb);
766 
767     //
768     // Allocate the TEB
769     //
770     Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
771     if (!NT_SUCCESS(Status))
772     {
773         /* Cleanup and exit */
774         KeDetachProcess();
775         return Status;
776     }
777 
778     //
779     // Use SEH in case we can't load the TEB
780     //
781     _SEH2_TRY
782     {
783         //
784         // Initialize the PEB
785         //
786         RtlZeroMemory(Teb, sizeof(TEB));
787 
788         //
789         // Set TIB Data
790         //
791 #ifdef _M_AMD64
792         Teb->NtTib.ExceptionList = NULL;
793 #else
794         Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
795 #endif
796         Teb->NtTib.Self = (PNT_TIB)Teb;
797 
798         //
799         // Identify this as an OS/2 V3.0 ("Cruiser") TIB
800         //
801         Teb->NtTib.Version = 30 << 8;
802 
803         //
804         // Set TEB Data
805         //
806         Teb->ClientId = *ClientId;
807         Teb->RealClientId = *ClientId;
808         Teb->ProcessEnvironmentBlock = Process->Peb;
809         Teb->CurrentLocale = PsDefaultThreadLocaleId;
810 
811         //
812         // Check if we have a grandparent TEB
813         //
814         if ((InitialTeb->PreviousStackBase == NULL) &&
815             (InitialTeb->PreviousStackLimit == NULL))
816         {
817             //
818             // Use initial TEB values
819             //
820             Teb->NtTib.StackBase = InitialTeb->StackBase;
821             Teb->NtTib.StackLimit = InitialTeb->StackLimit;
822             Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
823         }
824         else
825         {
826             //
827             // Use grandparent TEB values
828             //
829             Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
830             Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
831         }
832 
833         //
834         // Initialize the static unicode string
835         //
836         Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
837         Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
838     }
839     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
840     {
841         //
842         // Get error code
843         //
844         Status = _SEH2_GetExceptionCode();
845     }
846     _SEH2_END;
847 
848     //
849     // Return
850     //
851     KeDetachProcess();
852     *BaseTeb = Teb;
853     return Status;
854 }
855 
856 #ifdef _M_AMD64
857 static
858 NTSTATUS
MiInsertSharedUserPageVad(_In_ PEPROCESS Process)859 MiInsertSharedUserPageVad(
860     _In_ PEPROCESS Process)
861 {
862     PMMVAD_LONG Vad;
863     ULONG_PTR BaseAddress;
864     NTSTATUS Status;
865 
866     if (Process->QuotaBlock != NULL)
867     {
868         Status = PsChargeProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
869         if (!NT_SUCCESS(Status))
870         {
871             DPRINT1("Ran out of quota.\n");
872             return Status;
873         }
874     }
875 
876     /* Allocate a VAD */
877     Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
878     if (Vad == NULL)
879     {
880         DPRINT1("Failed to allocate VAD for shared user page\n");
881         Status = STATUS_INSUFFICIENT_RESOURCES;
882         goto FailPath;
883     }
884 
885     /* Setup the primary flags with the size, and make it private, RO */
886     Vad->u.LongFlags = 0;
887     Vad->u.VadFlags.CommitCharge = 0;
888     Vad->u.VadFlags.NoChange = TRUE;
889     Vad->u.VadFlags.VadType = VadNone;
890     Vad->u.VadFlags.MemCommit = FALSE;
891     Vad->u.VadFlags.Protection = MM_READONLY;
892     Vad->u.VadFlags.PrivateMemory = TRUE;
893     Vad->u1.Parent = NULL;
894 
895     /* Setup the secondary flags to make it a secured, readonly, long VAD */
896     Vad->u2.LongFlags2 = 0;
897     Vad->u2.VadFlags2.OneSecured = TRUE;
898     Vad->u2.VadFlags2.LongVad = TRUE;
899     Vad->u2.VadFlags2.ReadOnly = FALSE;
900 
901     Vad->ControlArea = NULL; // For Memory-Area hack
902     Vad->FirstPrototypePte = NULL;
903 
904     /* Insert it into the process VAD table */
905     BaseAddress = MM_SHARED_USER_DATA_VA;
906     Status = MiInsertVadEx((PMMVAD)Vad,
907                             &BaseAddress,
908                             PAGE_SIZE,
909                             (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
910                             PAGE_SIZE,
911                             MEM_TOP_DOWN);
912     if (!NT_SUCCESS(Status))
913     {
914         DPRINT1("Failed to insert shared user VAD\n");
915         ExFreePoolWithTag(Vad, 'ldaV');
916         goto FailPath;
917     }
918 
919     /* Success */
920     return STATUS_SUCCESS;
921 
922 FailPath:
923     if (Process->QuotaBlock != NULL)
924         PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
925 
926     return Status;
927 }
928 #endif
929 
930 NTSTATUS
931 NTAPI
MmInitializeProcessAddressSpace(IN PEPROCESS Process,IN PEPROCESS ProcessClone OPTIONAL,IN PVOID Section OPTIONAL,IN OUT PULONG Flags,IN POBJECT_NAME_INFORMATION * AuditName OPTIONAL)932 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
933                                 IN PEPROCESS ProcessClone OPTIONAL,
934                                 IN PVOID Section OPTIONAL,
935                                 IN OUT PULONG Flags,
936                                 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
937 {
938     NTSTATUS Status = STATUS_SUCCESS;
939     SIZE_T ViewSize = 0;
940     PVOID ImageBase = 0;
941     PMMPTE PointerPte;
942     KIRQL OldIrql;
943     PMMPDE PointerPde;
944     PMMPFN Pfn;
945     PFN_NUMBER PageFrameNumber;
946     UNICODE_STRING FileName;
947     PWCHAR Source;
948     PCHAR Destination;
949     USHORT Length = 0;
950 
951 #if (_MI_PAGING_LEVELS >= 3)
952     PMMPPE PointerPpe;
953 #endif
954 #if (_MI_PAGING_LEVELS == 4)
955     PMMPXE PointerPxe;
956 #endif
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 our working set */
978     MiLockProcessWorkingSet(Process, PsGetCurrentThread());
979 
980     /* Lock PFN database */
981     OldIrql = MiAcquirePfnLock();
982 
983     /* Setup the PFN for the PDE base of this process */
984 #if (_MI_PAGING_LEVELS == 4)
985     PointerPte = MiAddressToPte(PXE_BASE);
986 #elif (_MI_PAGING_LEVELS == 3)
987     PointerPte = MiAddressToPte(PPE_BASE);
988 #else
989     PointerPte = MiAddressToPte(PDE_BASE);
990 #endif
991     PageFrameNumber = PFN_FROM_PTE(PointerPte);
992     ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE);
993     MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
994 
995     /* Do the same for hyperspace */
996     PointerPde = MiAddressToPde(HYPER_SPACE);
997     PageFrameNumber = PFN_FROM_PTE(PointerPde);
998     MiInitializePfn(PageFrameNumber, (PMMPTE)PointerPde, TRUE);
999 #if (_MI_PAGING_LEVELS == 2)
1000     ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE);
1001 #endif
1002 
1003 #if (_MI_PAGING_LEVELS >= 3)
1004     PointerPpe = MiAddressToPpe((PVOID)HYPER_SPACE);
1005     PageFrameNumber = PFN_FROM_PTE(PointerPpe);
1006     MiInitializePfn(PageFrameNumber, PointerPpe, TRUE);
1007 #if (_MI_PAGING_LEVELS == 3)
1008     ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE);
1009 #endif
1010 #endif
1011 #if (_MI_PAGING_LEVELS == 4)
1012     PointerPxe = MiAddressToPxe((PVOID)HYPER_SPACE);
1013     PageFrameNumber = PFN_FROM_PTE(PointerPxe);
1014     MiInitializePfn(PageFrameNumber, PointerPxe, TRUE);
1015     ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE);
1016 #endif
1017 
1018     /* Do the same for the Working set list */
1019     PointerPte = MiAddressToPte(MmWorkingSetList);
1020     PageFrameNumber = PFN_FROM_PTE(PointerPte);
1021     MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
1022 
1023     /* All our pages are now active & valid. Release the lock. */
1024     MiReleasePfnLock(OldIrql);
1025 
1026     /* This should be in hyper space, but not in the mapping range */
1027     Process->Vm.VmWorkingSetList = MmWorkingSetList;
1028     ASSERT(((ULONG_PTR)MmWorkingSetList >= MI_MAPPING_RANGE_END) && ((ULONG_PTR)MmWorkingSetList <= HYPER_SPACE_END));
1029 
1030     /* Now initialize the working set list */
1031     MiInitializeWorkingSetList(&Process->Vm);
1032 
1033     /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
1034     Pfn = MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT);
1035     ASSERT(Pfn->u4.PteFrame == MiGetPfnEntryIndex(Pfn));
1036     ASSERT(Pfn->u1.WsIndex == 0);
1037     Pfn->u1.Event = (PKEVENT)Process;
1038 
1039     /* Sanity check */
1040     ASSERT(Process->PhysicalVadRoot == NULL);
1041 
1042     /* Release the process working set */
1043     MiUnlockProcessWorkingSet(Process, PsGetCurrentThread());
1044 
1045 #ifdef _M_AMD64
1046     /* On x64 we need a VAD for the shared user page */
1047     Status = MiInsertSharedUserPageVad(Process);
1048     if (!NT_SUCCESS(Status))
1049     {
1050         DPRINT1("MiCreateSharedUserPageVad() failed: 0x%lx\n", Status);
1051         return Status;
1052     }
1053 #endif
1054 
1055     /* Check if there's a Section Object */
1056     if (Section)
1057     {
1058         /* Determine the image file name and save it to EPROCESS */
1059         PFILE_OBJECT FileObject = MmGetFileObjectForSection(Section);
1060         FileName = FileObject->FileName;
1061         Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
1062         if (FileName.Buffer)
1063         {
1064             /* Loop the file name*/
1065             while (Source > FileName.Buffer)
1066             {
1067                 /* Make sure this isn't a backslash */
1068                 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
1069                 {
1070                     /* If so, stop it here */
1071                     Source++;
1072                     break;
1073                 }
1074                 else
1075                 {
1076                     /* Otherwise, keep going */
1077                     Length++;
1078                 }
1079             }
1080         }
1081 
1082         /* Copy the to the process and truncate it to 15 characters if necessary */
1083         Destination = Process->ImageFileName;
1084         Length = min(Length, sizeof(Process->ImageFileName) - 1);
1085         while (Length--) *Destination++ = (UCHAR)*Source++;
1086         *Destination = ANSI_NULL;
1087 
1088         /* Check if caller wants an audit name */
1089         if (AuditName)
1090         {
1091             /* Setup the audit name */
1092             Status = SeInitializeProcessAuditName(FileObject, FALSE, AuditName);
1093             if (!NT_SUCCESS(Status))
1094             {
1095                 /* Fail */
1096                 KeDetachProcess();
1097                 return Status;
1098             }
1099         }
1100 
1101         /* Map the section */
1102         Status = MmMapViewOfSection(Section,
1103                                     Process,
1104                                     (PVOID*)&ImageBase,
1105                                     0,
1106                                     0,
1107                                     NULL,
1108                                     &ViewSize,
1109                                     ViewUnmap,
1110                                     MEM_COMMIT,
1111                                     PAGE_READWRITE);
1112 
1113         /* Save the pointer */
1114         Process->SectionBaseAddress = ImageBase;
1115     }
1116 
1117     /* Be nice and detach */
1118     KeDetachProcess();
1119 
1120     /* Return status to caller */
1121     return Status;
1122 }
1123 
1124 CODE_SEG("INIT")
1125 NTSTATUS
1126 NTAPI
MmInitializeHandBuiltProcess(IN PEPROCESS Process,IN PULONG_PTR DirectoryTableBase)1127 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
1128                              IN PULONG_PTR DirectoryTableBase)
1129 {
1130     /* Share the directory base with the idle process */
1131     DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
1132     DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
1133 
1134     /* Initialize the Addresss Space */
1135     KeInitializeGuardedMutex(&Process->AddressCreationLock);
1136     KeInitializeSpinLock(&Process->HyperSpaceLock);
1137     Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
1138     ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
1139     Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
1140 
1141     /* Use idle process Working set */
1142     Process->Vm.VmWorkingSetList = PsGetCurrentProcess()->Vm.VmWorkingSetList;
1143     Process->WorkingSetPage = PsGetCurrentProcess()->WorkingSetPage;
1144 
1145     /* Done */
1146     Process->HasAddressSpace = TRUE;//??
1147     return STATUS_SUCCESS;
1148 }
1149 
1150 CODE_SEG("INIT")
1151 NTSTATUS
1152 NTAPI
MmInitializeHandBuiltProcess2(IN PEPROCESS Process)1153 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
1154 {
1155     /* Lock the VAD, ARM3-owned ranges away */
1156     return STATUS_SUCCESS;
1157 }
1158 
1159 BOOLEAN
1160 NTAPI
MmCreateProcessAddressSpace(IN ULONG MinWs,IN PEPROCESS Process,OUT PULONG_PTR DirectoryTableBase)1161 MmCreateProcessAddressSpace(IN ULONG MinWs,
1162                             IN PEPROCESS Process,
1163                             OUT PULONG_PTR DirectoryTableBase)
1164 {
1165     KIRQL OldIrql;
1166     PFN_NUMBER TableBaseIndex, HyperIndex, WsListIndex;
1167     ULONG Color;
1168 
1169     /* Make sure we don't already have a page directory setup */
1170     ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
1171     ASSERT(Process->Pcb.DirectoryTableBase[1] == 0);
1172     ASSERT(Process->WorkingSetPage == 0);
1173 
1174     /* Choose a process color */
1175     Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
1176 
1177     /* Setup the hyperspace lock */
1178     KeInitializeSpinLock(&Process->HyperSpaceLock);
1179 
1180     /* Lock PFN database */
1181     OldIrql = MiAcquirePfnLock();
1182 
1183     /*
1184      * Get a page for the table base, one for hyper space & one for the working set list.
1185      * The PFNs for these pages will be initialized in MmInitializeProcessAddressSpace,
1186      * when we are already attached to the process.
1187      * The other pages (if any) are allocated in the arch-specific part.
1188      */
1189     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1190     MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1191     TableBaseIndex = MiRemoveZeroPageSafe(Color);
1192     if (!TableBaseIndex)
1193     {
1194         /* No zero pages, grab a free one */
1195         TableBaseIndex = MiRemoveAnyPage(Color);
1196 
1197         /* Zero it outside the PFN lock */
1198         MiReleasePfnLock(OldIrql);
1199         MiZeroPhysicalPage(TableBaseIndex);
1200         OldIrql = MiAcquirePfnLock();
1201     }
1202     MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1203     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1204     HyperIndex = MiRemoveZeroPageSafe(Color);
1205     if (!HyperIndex)
1206     {
1207         /* No zero pages, grab a free one */
1208         HyperIndex = MiRemoveAnyPage(Color);
1209 
1210         /* Zero it outside the PFN lock */
1211         MiReleasePfnLock(OldIrql);
1212         MiZeroPhysicalPage(HyperIndex);
1213         OldIrql = MiAcquirePfnLock();
1214     }
1215     MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
1216     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1217     WsListIndex = MiRemoveZeroPageSafe(Color);
1218     if (!WsListIndex)
1219     {
1220         /* No zero pages, grab a free one */
1221         WsListIndex = MiRemoveAnyPage(Color);
1222 
1223         /* Zero it outside the PFN lock */
1224         MiReleasePfnLock(OldIrql);
1225         MiZeroPhysicalPage(WsListIndex);
1226     }
1227     else
1228     {
1229         /* Release the PFN lock */
1230         MiReleasePfnLock(OldIrql);
1231     }
1232 
1233     /* Set the base directory pointers */
1234     Process->WorkingSetPage = WsListIndex;
1235     DirectoryTableBase[0] = TableBaseIndex << PAGE_SHIFT;
1236     DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
1237 
1238     /* Perform the arch-specific parts */
1239     if (!MiArchCreateProcessAddressSpace(Process, DirectoryTableBase))
1240     {
1241         OldIrql = MiAcquirePfnLock();
1242         MiInsertPageInFreeList(WsListIndex);
1243         MiInsertPageInFreeList(HyperIndex);
1244         MiInsertPageInFreeList(TableBaseIndex);
1245         MiReleasePfnLock(OldIrql);
1246         Process->WorkingSetPage = 0;
1247         DirectoryTableBase[0] = 0;
1248         DirectoryTableBase[1] = 0;
1249         return FALSE;
1250     }
1251 
1252     /* Switch to phase 1 initialization */
1253     ASSERT(Process->AddressSpaceInitialized == 0);
1254     Process->AddressSpaceInitialized = 1;
1255 
1256     /* Add the process to the session */
1257     MiSessionAddProcess(Process);
1258     return TRUE;
1259 }
1260 
1261 VOID
1262 NTAPI
MmCleanProcessAddressSpace(IN PEPROCESS Process)1263 MmCleanProcessAddressSpace(IN PEPROCESS Process)
1264 {
1265     PMMVAD Vad;
1266     PMM_AVL_TABLE VadTree;
1267     PETHREAD Thread = PsGetCurrentThread();
1268 
1269     /* Remove from the session */
1270     MiSessionRemoveProcess();
1271 
1272     /* Abort early, when the address space wasn't fully initialized */
1273     if (Process->AddressSpaceInitialized < 2)
1274     {
1275         DPRINT1("Incomplete address space for Process %p. Might leak resources.\n",
1276                 Process);
1277         return;
1278     }
1279 
1280     /* Lock the process address space from changes */
1281     MmLockAddressSpace(&Process->Vm);
1282     MiLockProcessWorkingSetUnsafe(Process, Thread);
1283 
1284     /* VM is deleted now */
1285     Process->VmDeleted = TRUE;
1286     MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1287 
1288     /* Enumerate the VADs */
1289     VadTree = &Process->VadRoot;
1290     while (VadTree->NumberGenericTableElements)
1291     {
1292         /* Grab the current VAD */
1293         Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
1294 
1295         /* Check for old-style memory areas */
1296         if (Vad->u.VadFlags.Spare == 1)
1297         {
1298             /* Let RosMm handle this */
1299             MiRosCleanupMemoryArea(Process, Vad);
1300             continue;
1301         }
1302 
1303         /* Lock the working set */
1304         MiLockProcessWorkingSetUnsafe(Process, Thread);
1305 
1306         /* Remove this VAD from the tree */
1307         ASSERT(VadTree->NumberGenericTableElements >= 1);
1308         MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
1309 
1310         /* Only regular VADs supported for now */
1311         ASSERT(Vad->u.VadFlags.VadType == VadNone);
1312 
1313         /* Check if this is a section VAD */
1314         if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
1315         {
1316             /* Remove the view */
1317             MiRemoveMappedView(Process, Vad);
1318         }
1319         else
1320         {
1321             /* Delete the addresses */
1322             MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
1323                                      (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
1324                                      Vad);
1325 
1326             /* Release the working set */
1327             MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1328         }
1329 
1330          /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1331         if (Vad->u.VadFlags.Spare == 1)
1332         {
1333             /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1334             Vad->u.VadFlags.Spare = 2;
1335             continue;
1336         }
1337 
1338         /* Free the VAD memory */
1339         ExFreePool(Vad);
1340 
1341         /* Return the quota the VAD used */
1342         PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG));
1343     }
1344 
1345     /* Lock the working set */
1346     MiLockProcessWorkingSetUnsafe(Process, Thread);
1347     ASSERT(Process->CloneRoot == NULL);
1348     ASSERT(Process->PhysicalVadRoot == NULL);
1349 
1350     /* Delete the shared user data section */
1351     MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
1352 
1353     /* Release the working set */
1354     MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1355 
1356     /* Release the address space */
1357     MmUnlockAddressSpace(&Process->Vm);
1358 }
1359 
1360 VOID
1361 NTAPI
MmDeleteProcessAddressSpace(IN PEPROCESS Process)1362 MmDeleteProcessAddressSpace(IN PEPROCESS Process)
1363 {
1364     PMMPFN Pfn1, Pfn2;
1365     KIRQL OldIrql;
1366     PFN_NUMBER PageFrameIndex;
1367 
1368 #ifndef _M_AMD64
1369     OldIrql = MiAcquireExpansionLock();
1370     RemoveEntryList(&Process->MmProcessLinks);
1371     MiReleaseExpansionLock(OldIrql);
1372 #endif
1373 
1374     //ASSERT(Process->CommitCharge == 0);
1375 
1376     /* Remove us from the list */
1377     OldIrql = MiAcquireExpansionLock();
1378     if (Process->Vm.WorkingSetExpansionLinks.Flink != NULL)
1379         RemoveEntryList(&Process->Vm.WorkingSetExpansionLinks);
1380     MiReleaseExpansionLock(OldIrql);
1381 
1382     /* Acquire the PFN lock */
1383     OldIrql = MiAcquirePfnLock();
1384 
1385     /* Check for fully initialized process */
1386     if (Process->AddressSpaceInitialized == 2)
1387     {
1388         /* Map the working set page and its page table */
1389         Pfn1 = MiGetPfnEntry(Process->WorkingSetPage);
1390         Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
1391 
1392         /* Nuke it */
1393         MI_SET_PFN_DELETED(Pfn1);
1394         MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
1395         MiDecrementShareCount(Pfn1, Process->WorkingSetPage);
1396         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1397 
1398         /* Now map hyperspace and its page table */
1399         PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT;
1400         Pfn1 = MiGetPfnEntry(PageFrameIndex);
1401         Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
1402 
1403         /* Nuke it */
1404         MI_SET_PFN_DELETED(Pfn1);
1405         MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
1406         MiDecrementShareCount(Pfn1, PageFrameIndex);
1407         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1408 
1409         /* Finally, nuke the PDE itself */
1410         PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
1411         Pfn1 = MiGetPfnEntry(PageFrameIndex);
1412         MI_SET_PFN_DELETED(Pfn1);
1413         MiDecrementShareCount(Pfn1, PageFrameIndex);
1414         MiDecrementShareCount(Pfn1, PageFrameIndex);
1415 
1416         /* Page table is now dead. Bye bye... */
1417         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1418     }
1419     else
1420     {
1421         DPRINT1("Deleting partially initialized address space of Process %p. Might leak resources.\n",
1422                 Process);
1423     }
1424 
1425     /* Release the PFN lock */
1426     MiReleasePfnLock(OldIrql);
1427 
1428     /* Drop a reference on the session */
1429     if (Process->Session) MiReleaseProcessReferenceToSessionDataPage(Process->Session);
1430 
1431     /* Clear out the PDE pages */
1432     Process->Pcb.DirectoryTableBase[0] = 0;
1433     Process->Pcb.DirectoryTableBase[1] = 0;
1434 }
1435 
1436 
1437 /* SYSTEM CALLS ***************************************************************/
1438 
1439 NTSTATUS
1440 NTAPI
NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,IN OUT PULONG_PTR NumberOfPages,IN OUT PULONG_PTR UserPfnArray)1441 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
1442                             IN OUT PULONG_PTR NumberOfPages,
1443                             IN OUT PULONG_PTR UserPfnArray)
1444 {
1445     UNIMPLEMENTED;
1446     return STATUS_NOT_IMPLEMENTED;
1447 }
1448 
1449 NTSTATUS
1450 NTAPI
NtMapUserPhysicalPages(IN PVOID VirtualAddresses,IN ULONG_PTR NumberOfPages,IN OUT PULONG_PTR UserPfnArray)1451 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
1452                        IN ULONG_PTR NumberOfPages,
1453                        IN OUT PULONG_PTR UserPfnArray)
1454 {
1455     UNIMPLEMENTED;
1456     return STATUS_NOT_IMPLEMENTED;
1457 }
1458 
1459 NTSTATUS
1460 NTAPI
NtMapUserPhysicalPagesScatter(IN PVOID * VirtualAddresses,IN ULONG_PTR NumberOfPages,IN OUT PULONG_PTR UserPfnArray)1461 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
1462                               IN ULONG_PTR NumberOfPages,
1463                               IN OUT PULONG_PTR UserPfnArray)
1464 {
1465     UNIMPLEMENTED;
1466     return STATUS_NOT_IMPLEMENTED;
1467 }
1468 
1469 NTSTATUS
1470 NTAPI
NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,IN OUT PULONG_PTR NumberOfPages,IN OUT PULONG_PTR UserPfnArray)1471 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
1472                         IN OUT PULONG_PTR NumberOfPages,
1473                         IN OUT PULONG_PTR UserPfnArray)
1474 {
1475     UNIMPLEMENTED;
1476     return STATUS_NOT_IMPLEMENTED;
1477 }
1478 
1479 /* EOF */
1480