e415a6e27b61f576c3590e6e1bd351224e7062fc
[reactos.git] / 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 if (!NT_SUCCESS(Status))
761 {
762 /* Cleanup and exit */
763 KeDetachProcess();
764 return Status;
765 }
766
767 //
768 // Use SEH in case we can't load the TEB
769 //
770 _SEH2_TRY
771 {
772 //
773 // Initialize the PEB
774 //
775 RtlZeroMemory(Teb, sizeof(TEB));
776
777 //
778 // Set TIB Data
779 //
780 #ifdef _M_AMD64
781 Teb->NtTib.ExceptionList = NULL;
782 #else
783 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
784 #endif
785 Teb->NtTib.Self = (PNT_TIB)Teb;
786
787 //
788 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
789 //
790 Teb->NtTib.Version = 30 << 8;
791
792 //
793 // Set TEB Data
794 //
795 Teb->ClientId = *ClientId;
796 Teb->RealClientId = *ClientId;
797 Teb->ProcessEnvironmentBlock = Process->Peb;
798 Teb->CurrentLocale = PsDefaultThreadLocaleId;
799
800 //
801 // Check if we have a grandparent TEB
802 //
803 if ((InitialTeb->PreviousStackBase == NULL) &&
804 (InitialTeb->PreviousStackLimit == NULL))
805 {
806 //
807 // Use initial TEB values
808 //
809 Teb->NtTib.StackBase = InitialTeb->StackBase;
810 Teb->NtTib.StackLimit = InitialTeb->StackLimit;
811 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
812 }
813 else
814 {
815 //
816 // Use grandparent TEB values
817 //
818 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
819 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
820 }
821
822 //
823 // Initialize the static unicode string
824 //
825 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
826 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
827 }
828 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
829 {
830 //
831 // Get error code
832 //
833 Status = _SEH2_GetExceptionCode();
834 }
835 _SEH2_END;
836
837 //
838 // Return
839 //
840 KeDetachProcess();
841 *BaseTeb = Teb;
842 return Status;
843 }
844
845 VOID
846 NTAPI
847 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
848 {
849 PMMPFN Pfn1;
850 PMMPTE sysPte;
851 MMPTE tempPte;
852
853 /* Setup some bogus list data */
854 MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
855 MmWorkingSetList->HashTable = NULL;
856 MmWorkingSetList->HashTableSize = 0;
857 MmWorkingSetList->NumberOfImageWaiters = 0;
858 MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
859 MmWorkingSetList->VadBitMapHint = 1;
860 MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
861 MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
862 MmWorkingSetList->FirstFree = 1;
863 MmWorkingSetList->FirstDynamic = 2;
864 MmWorkingSetList->NextSlot = 3;
865 MmWorkingSetList->LastInitializedWsle = 4;
866
867 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
868 Pfn1 = MiGetPfnEntry(CurrentProcess->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT);
869 ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
870 Pfn1->u1.Event = (PKEVENT)CurrentProcess;
871
872 /* Map the process working set in kernel space */
873 sysPte = MiReserveSystemPtes(1, SystemPteSpace);
874 MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte, sysPte, MM_READWRITE, CurrentProcess->WorkingSetPage);
875 MI_WRITE_VALID_PTE(sysPte, tempPte);
876 CurrentProcess->Vm.VmWorkingSetList = MiPteToAddress(sysPte);
877 }
878
879 NTSTATUS
880 NTAPI
881 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
882 IN PEPROCESS ProcessClone OPTIONAL,
883 IN PVOID Section OPTIONAL,
884 IN OUT PULONG Flags,
885 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
886 {
887 NTSTATUS Status = STATUS_SUCCESS;
888 SIZE_T ViewSize = 0;
889 PVOID ImageBase = 0;
890 PROS_SECTION_OBJECT SectionObject = Section;
891 PMMPTE PointerPte;
892 KIRQL OldIrql;
893 PMMPDE PointerPde;
894 PFN_NUMBER PageFrameNumber;
895 UNICODE_STRING FileName;
896 PWCHAR Source;
897 PCHAR Destination;
898 USHORT Length = 0;
899 MMPTE TempPte;
900
901 /* We should have a PDE */
902 ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
903 ASSERT(Process->PdeUpdateNeeded == FALSE);
904
905 /* Attach to the process */
906 KeAttachProcess(&Process->Pcb);
907
908 /* The address space should now been in phase 1 or 0 */
909 ASSERT(Process->AddressSpaceInitialized <= 1);
910 Process->AddressSpaceInitialized = 2;
911
912 /* Initialize the Addresss Space lock */
913 KeInitializeGuardedMutex(&Process->AddressCreationLock);
914 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
915
916 /* Initialize AVL tree */
917 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
918 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
919
920 /* Lock PFN database */
921 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
922
923 /* Setup the PFN for the PDE base of this process */
924 #ifdef _M_AMD64
925 PointerPte = MiAddressToPte(PXE_BASE);
926 #else
927 PointerPte = MiAddressToPte(PDE_BASE);
928 #endif
929 PageFrameNumber = PFN_FROM_PTE(PointerPte);
930 ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE);
931 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
932
933 /* Do the same for hyperspace */
934 #ifdef _M_AMD64
935 PointerPde = MiAddressToPxe((PVOID)HYPER_SPACE);
936 #else
937 PointerPde = MiAddressToPde(HYPER_SPACE);
938 #endif
939 PageFrameNumber = PFN_FROM_PTE(PointerPde);
940 //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
941 MiInitializePfn(PageFrameNumber, (PMMPTE)PointerPde, TRUE);
942
943 /* Setup the PFN for the PTE for the working set */
944 PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
945 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
946 ASSERT(PointerPte->u.Long != 0);
947 PageFrameNumber = PFN_FROM_PTE(PointerPte);
948 MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
949 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
950 TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
951 MI_WRITE_VALID_PTE(PointerPte, TempPte);
952
953 /* Now initialize the working set list */
954 MiInitializeWorkingSetList(Process);
955
956 /* Sanity check */
957 ASSERT(Process->PhysicalVadRoot == NULL);
958
959 /* Release PFN lock */
960 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
961
962 /* Check if there's a Section Object */
963 if (SectionObject)
964 {
965 /* Determine the image file name and save it to EPROCESS */
966 FileName = SectionObject->FileObject->FileName;
967 Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
968 if (FileName.Buffer)
969 {
970 /* Loop the file name*/
971 while (Source > FileName.Buffer)
972 {
973 /* Make sure this isn't a backslash */
974 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
975 {
976 /* If so, stop it here */
977 Source++;
978 break;
979 }
980 else
981 {
982 /* Otherwise, keep going */
983 Length++;
984 }
985 }
986 }
987
988 /* Copy the to the process and truncate it to 15 characters if necessary */
989 Destination = Process->ImageFileName;
990 Length = min(Length, sizeof(Process->ImageFileName) - 1);
991 while (Length--) *Destination++ = (UCHAR)*Source++;
992 *Destination = ANSI_NULL;
993
994 /* Check if caller wants an audit name */
995 if (AuditName)
996 {
997 /* Setup the audit name */
998 Status = SeInitializeProcessAuditName(SectionObject->FileObject,
999 FALSE,
1000 AuditName);
1001 if (!NT_SUCCESS(Status))
1002 {
1003 /* Fail */
1004 KeDetachProcess();
1005 return Status;
1006 }
1007 }
1008
1009 /* Map the section */
1010 Status = MmMapViewOfSection(Section,
1011 Process,
1012 (PVOID*)&ImageBase,
1013 0,
1014 0,
1015 NULL,
1016 &ViewSize,
1017 0,
1018 MEM_COMMIT,
1019 PAGE_READWRITE);
1020
1021 /* Save the pointer */
1022 Process->SectionBaseAddress = ImageBase;
1023 }
1024
1025 /* Be nice and detach */
1026 KeDetachProcess();
1027
1028 /* Return status to caller */
1029 return Status;
1030 }
1031
1032 NTSTATUS
1033 NTAPI
1034 INIT_FUNCTION
1035 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
1036 IN PULONG_PTR DirectoryTableBase)
1037 {
1038 /* Share the directory base with the idle process */
1039 DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
1040 DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
1041
1042 /* Initialize the Addresss Space */
1043 KeInitializeGuardedMutex(&Process->AddressCreationLock);
1044 KeInitializeSpinLock(&Process->HyperSpaceLock);
1045 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
1046 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
1047 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
1048
1049 /* Use idle process Working set */
1050 Process->Vm.VmWorkingSetList = PsGetCurrentProcess()->Vm.VmWorkingSetList;
1051
1052 /* Done */
1053 Process->HasAddressSpace = TRUE;//??
1054 return STATUS_SUCCESS;
1055 }
1056
1057 NTSTATUS
1058 NTAPI
1059 INIT_FUNCTION
1060 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
1061 {
1062 /* Lock the VAD, ARM3-owned ranges away */
1063 return STATUS_SUCCESS;
1064 }
1065
1066 #ifdef _M_IX86
1067 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1068 BOOLEAN
1069 NTAPI
1070 MmCreateProcessAddressSpace(IN ULONG MinWs,
1071 IN PEPROCESS Process,
1072 OUT PULONG_PTR DirectoryTableBase)
1073 {
1074 KIRQL OldIrql;
1075 PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
1076 PMMPTE PointerPte;
1077 MMPTE TempPte, PdePte;
1078 ULONG PdeOffset;
1079 PMMPTE SystemTable, HyperTable;
1080 ULONG Color;
1081 PMMPFN Pfn1;
1082
1083 /* Choose a process color */
1084 Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
1085
1086 /* Setup the hyperspace lock */
1087 KeInitializeSpinLock(&Process->HyperSpaceLock);
1088
1089 /* Lock PFN database */
1090 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1091
1092 /* Get a zero page for the PDE, if possible */
1093 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1094 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1095 PdeIndex = MiRemoveZeroPageSafe(Color);
1096 if (!PdeIndex)
1097 {
1098 /* No zero pages, grab a free one */
1099 PdeIndex = MiRemoveAnyPage(Color);
1100
1101 /* Zero it outside the PFN lock */
1102 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1103 MiZeroPhysicalPage(PdeIndex);
1104 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1105 }
1106
1107 /* Get a zero page for hyperspace, if possible */
1108 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
1109 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1110 HyperIndex = MiRemoveZeroPageSafe(Color);
1111 if (!HyperIndex)
1112 {
1113 /* No zero pages, grab a free one */
1114 HyperIndex = MiRemoveAnyPage(Color);
1115
1116 /* Zero it outside the PFN lock */
1117 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1118 MiZeroPhysicalPage(HyperIndex);
1119 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1120 }
1121
1122 /* Get a zero page for the woring set list, if possible */
1123 MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
1124 Color = MI_GET_NEXT_PROCESS_COLOR(Process);
1125 WsListIndex = MiRemoveZeroPageSafe(Color);
1126 if (!WsListIndex)
1127 {
1128 /* No zero pages, grab a free one */
1129 WsListIndex = MiRemoveAnyPage(Color);
1130
1131 /* Zero it outside the PFN lock */
1132 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1133 MiZeroPhysicalPage(WsListIndex);
1134 }
1135 else
1136 {
1137 /* Release the PFN lock */
1138 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1139 }
1140
1141 /* Switch to phase 1 initialization */
1142 ASSERT(Process->AddressSpaceInitialized == 0);
1143 Process->AddressSpaceInitialized = 1;
1144
1145 /* Set the base directory pointers */
1146 Process->WorkingSetPage = WsListIndex;
1147 DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
1148 DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
1149
1150 /* Make sure we don't already have a page directory setup */
1151 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
1152
1153 /* Get a PTE to map hyperspace */
1154 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1155 ASSERT(PointerPte != NULL);
1156
1157 /* Build it */
1158 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1159 PointerPte,
1160 MM_READWRITE,
1161 HyperIndex);
1162
1163 /* Set it dirty and map it */
1164 MI_MAKE_DIRTY_PAGE(&PdePte);
1165 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1166
1167 /* Now get hyperspace's page table */
1168 HyperTable = MiPteToAddress(PointerPte);
1169
1170 /* Now write the PTE/PDE entry for the working set list index itself */
1171 TempPte = ValidKernelPteLocal;
1172 TempPte.u.Hard.PageFrameNumber = WsListIndex;
1173 PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
1174 HyperTable[PdeOffset] = TempPte;
1175
1176 /* Let go of the system PTE */
1177 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1178
1179 /* Save the PTE address of the page directory itself */
1180 Pfn1 = MiGetPfnEntry(PdeIndex);
1181 Pfn1->PteAddress = (PMMPTE)PDE_BASE;
1182
1183 /* Insert us into the Mm process list */
1184 OldIrql = MiAcquireExpansionLock();
1185 InsertTailList(&MmProcessList, &Process->MmProcessLinks);
1186 MiReleaseExpansionLock(OldIrql);
1187
1188 /* Get a PTE to map the page directory */
1189 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1190 ASSERT(PointerPte != NULL);
1191
1192 /* Build it */
1193 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1194 PointerPte,
1195 MM_READWRITE,
1196 PdeIndex);
1197
1198 /* Set it dirty and map it */
1199 MI_MAKE_DIRTY_PAGE(&PdePte);
1200 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1201
1202 /* Now get the page directory (which we'll double map, so call it a page table */
1203 SystemTable = MiPteToAddress(PointerPte);
1204
1205 /* Copy all the kernel mappings */
1206 PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
1207 RtlCopyMemory(&SystemTable[PdeOffset],
1208 MiAddressToPde(MmSystemRangeStart),
1209 PAGE_SIZE - PdeOffset * sizeof(MMPTE));
1210
1211 /* Now write the PTE/PDE entry for hyperspace itself */
1212 TempPte = ValidKernelPteLocal;
1213 TempPte.u.Hard.PageFrameNumber = HyperIndex;
1214 PdeOffset = MiGetPdeOffset(HYPER_SPACE);
1215 SystemTable[PdeOffset] = TempPte;
1216
1217 /* Sanity check */
1218 PdeOffset++;
1219 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
1220
1221 /* Now do the x86 trick of making the PDE a page table itself */
1222 PdeOffset = MiGetPdeOffset(PTE_BASE);
1223 TempPte.u.Hard.PageFrameNumber = PdeIndex;
1224 SystemTable[PdeOffset] = TempPte;
1225
1226 /* Let go of the system PTE */
1227 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1228
1229 /* Add the process to the session */
1230 MiSessionAddProcess(Process);
1231 return TRUE;
1232 }
1233 #endif
1234
1235 VOID
1236 NTAPI
1237 MmCleanProcessAddressSpace(IN PEPROCESS Process)
1238 {
1239 PMMVAD Vad;
1240 PMM_AVL_TABLE VadTree;
1241 PETHREAD Thread = PsGetCurrentThread();
1242
1243 /* Only support this */
1244 ASSERT(Process->AddressSpaceInitialized == 2);
1245
1246 /* Remove from the session */
1247 MiSessionRemoveProcess();
1248
1249 /* Lock the process address space from changes */
1250 MmLockAddressSpace(&Process->Vm);
1251 MiLockProcessWorkingSetUnsafe(Process, Thread);
1252
1253 /* VM is deleted now */
1254 Process->VmDeleted = TRUE;
1255 MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1256
1257 /* Enumerate the VADs */
1258 VadTree = &Process->VadRoot;
1259 while (VadTree->NumberGenericTableElements)
1260 {
1261 /* Grab the current VAD */
1262 Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
1263
1264 /* Check for old-style memory areas */
1265 if (Vad->u.VadFlags.Spare == 1)
1266 {
1267 /* Let RosMm handle this */
1268 MiRosCleanupMemoryArea(Process, Vad);
1269 continue;
1270 }
1271
1272 /* Lock the working set */
1273 MiLockProcessWorkingSetUnsafe(Process, Thread);
1274
1275 /* Remove this VAD from the tree */
1276 ASSERT(VadTree->NumberGenericTableElements >= 1);
1277 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
1278
1279 /* Only regular VADs supported for now */
1280 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1281
1282 /* Check if this is a section VAD */
1283 if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
1284 {
1285 /* Remove the view */
1286 MiRemoveMappedView(Process, Vad);
1287 }
1288 else
1289 {
1290 /* Delete the addresses */
1291 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
1292 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
1293 Vad);
1294
1295 /* Release the working set */
1296 MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1297 }
1298
1299 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
1300 if (Vad->u.VadFlags.Spare == 1)
1301 {
1302 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
1303 Vad->u.VadFlags.Spare = 2;
1304 continue;
1305 }
1306
1307 /* Free the VAD memory */
1308 ExFreePool(Vad);
1309 }
1310
1311 /* Lock the working set */
1312 MiLockProcessWorkingSetUnsafe(Process, Thread);
1313 ASSERT(Process->CloneRoot == NULL);
1314 ASSERT(Process->PhysicalVadRoot == NULL);
1315
1316 /* Delete the shared user data section */
1317 MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
1318
1319 /* Release the working set */
1320 MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1321
1322 /* Release the address space */
1323 MmUnlockAddressSpace(&Process->Vm);
1324 }
1325
1326 VOID
1327 NTAPI
1328 MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
1329 {
1330 PMMPFN Pfn1, Pfn2;
1331 KIRQL OldIrql;
1332 PFN_NUMBER PageFrameIndex;
1333
1334 //ASSERT(Process->CommitCharge == 0);
1335
1336 /* Acquire the PFN lock */
1337 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1338
1339 /* Check for fully initialized process */
1340 if (Process->AddressSpaceInitialized == 2)
1341 {
1342 /* Map the working set page and its page table */
1343 Pfn1 = MiGetPfnEntry(Process->WorkingSetPage);
1344 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
1345
1346 /* Nuke it */
1347 MI_SET_PFN_DELETED(Pfn1);
1348 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
1349 MiDecrementShareCount(Pfn1, Process->WorkingSetPage);
1350 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1351 MiReleaseSystemPtes(MiAddressToPte(Process->Vm.VmWorkingSetList), 1, SystemPteSpace);
1352
1353 /* Now map hyperspace and its page table */
1354 PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT;
1355 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1356 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
1357
1358 /* Nuke it */
1359 MI_SET_PFN_DELETED(Pfn1);
1360 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
1361 MiDecrementShareCount(Pfn1, PageFrameIndex);
1362 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1363
1364 /* Finally, nuke the PDE itself */
1365 PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
1366 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1367 MI_SET_PFN_DELETED(Pfn1);
1368 MiDecrementShareCount(Pfn1, PageFrameIndex);
1369 MiDecrementShareCount(Pfn1, PageFrameIndex);
1370
1371 /* Page table is now dead. Bye bye... */
1372 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
1373 }
1374 else
1375 {
1376 /* A partly-initialized process should never exit through here */
1377 ASSERT(FALSE);
1378 }
1379
1380 /* Release the PFN lock */
1381 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1382
1383 /* Drop a reference on the session */
1384 if (Process->Session) MiReleaseProcessReferenceToSessionDataPage(Process->Session);
1385
1386 /* Clear out the PDE pages */
1387 Process->Pcb.DirectoryTableBase[0] = 0;
1388 Process->Pcb.DirectoryTableBase[1] = 0;
1389 }
1390
1391
1392 /* SYSTEM CALLS ***************************************************************/
1393
1394 NTSTATUS
1395 NTAPI
1396 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
1397 IN OUT PULONG_PTR NumberOfPages,
1398 IN OUT PULONG_PTR UserPfnArray)
1399 {
1400 UNIMPLEMENTED;
1401 return STATUS_NOT_IMPLEMENTED;
1402 }
1403
1404 NTSTATUS
1405 NTAPI
1406 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
1407 IN ULONG_PTR NumberOfPages,
1408 IN OUT PULONG_PTR UserPfnArray)
1409 {
1410 UNIMPLEMENTED;
1411 return STATUS_NOT_IMPLEMENTED;
1412 }
1413
1414 NTSTATUS
1415 NTAPI
1416 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
1417 IN ULONG_PTR NumberOfPages,
1418 IN OUT PULONG_PTR UserPfnArray)
1419 {
1420 UNIMPLEMENTED;
1421 return STATUS_NOT_IMPLEMENTED;
1422 }
1423
1424 NTSTATUS
1425 NTAPI
1426 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
1427 IN OUT PULONG_PTR NumberOfPages,
1428 IN OUT PULONG_PTR UserPfnArray)
1429 {
1430 UNIMPLEMENTED;
1431 return STATUS_NOT_IMPLEMENTED;
1432 }
1433
1434 /* EOF */