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