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