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