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