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