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