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