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