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