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