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