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