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