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