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