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