[NTOSKRNL]
[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 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 PFN_NUMBER StackPages;
393 KIRQL OldIrql;
394 MMPTE TempPte, InvalidPte;
395 PFN_NUMBER PageFrameIndex;
396
397 //
398 // Make sure the stack did not overflow
399 //
400 ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
401 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
402
403 //
404 // Get the current stack limit
405 //
406 LimitPte = MiAddressToPte(Thread->StackLimit);
407 ASSERT(LimitPte->u.Hard.Valid == 1);
408
409 //
410 // Get the new one and make sure this isn't a retarded request
411 //
412 NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
413 if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
414
415 //
416 // Now make sure you're not going past the reserved space
417 //
418 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
419 KERNEL_LARGE_STACK_SIZE));
420 if (NewLimitPte < LastPte)
421 {
422 //
423 // Sorry!
424 //
425 DPRINT1("Thread wants too much stack\n");
426 return STATUS_STACK_OVERFLOW;
427 }
428
429 //
430 // Calculate the number of new pages
431 //
432 LimitPte--;
433 StackPages = (LimitPte - NewLimitPte + 1);
434
435 /* Setup the temporary invalid PTE */
436 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
437
438 //
439 // Acquire the PFN DB lock
440 //
441 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
442
443 //
444 // Loop each stack page
445 //
446 while (LimitPte >= NewLimitPte)
447 {
448 /* Get a page and write the current invalid PTE */
449 PageFrameIndex = MiRemoveAnyPage(0);
450 MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
451
452 /* Initialize the PFN entry for this page */
453 MiInitializePfn(PageFrameIndex, LimitPte, 1);
454
455 /* Setup the template stack PTE */
456 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
457
458 /* Write the valid PTE */
459 MI_WRITE_VALID_PTE(LimitPte--, TempPte);
460 }
461
462 //
463 // Release the PFN lock
464 //
465 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
466
467 //
468 // Set the new limit
469 //
470 Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
471 return STATUS_SUCCESS;
472 }
473
474 NTSTATUS
475 NTAPI
476 MmGrowKernelStack(IN PVOID StackPointer)
477 {
478 //
479 // Call the extended version
480 //
481 return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
482 }
483
484 NTSTATUS
485 NTAPI
486 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
487 IN UCHAR MemoryPriority)
488 {
489 UCHAR OldPriority;
490
491 //
492 // Check if we have less then 16MB of Physical Memory
493 //
494 if ((MmSystemSize == MmSmallSystem) &&
495 (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
496 {
497 //
498 // Always use background priority
499 //
500 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
501 }
502
503 //
504 // Save the old priority and update it
505 //
506 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
507 Process->Vm.Flags.MemoryPriority = MemoryPriority;
508
509 //
510 // Return the old priority
511 //
512 return OldPriority;
513 }
514
515 LCID
516 NTAPI
517 MmGetSessionLocaleId(VOID)
518 {
519 PEPROCESS Process;
520 PAGED_CODE();
521
522 //
523 // Get the current process
524 //
525 Process = PsGetCurrentProcess();
526
527 //
528 // Check if it's the Session Leader
529 //
530 if (Process->Vm.Flags.SessionLeader)
531 {
532 //
533 // Make sure it has a valid Session
534 //
535 if (Process->Session)
536 {
537 //
538 // Get the Locale ID
539 //
540 #if ROS_HAS_SESSIONS
541 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
542 #endif
543 }
544 }
545
546 //
547 // Not a session leader, return the default
548 //
549 return PsDefaultThreadLocaleId;
550 }
551
552 NTSTATUS
553 NTAPI
554 MmCreatePeb(IN PEPROCESS Process,
555 IN PINITIAL_PEB InitialPeb,
556 OUT PPEB *BasePeb)
557 {
558 PPEB Peb = NULL;
559 LARGE_INTEGER SectionOffset;
560 SIZE_T ViewSize = 0;
561 PVOID TableBase = NULL;
562 PIMAGE_NT_HEADERS NtHeaders;
563 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
564 NTSTATUS Status;
565 USHORT Characteristics;
566 KAFFINITY ProcessAffinityMask = 0;
567 SectionOffset.QuadPart = (ULONGLONG)0;
568 *BasePeb = NULL;
569
570 //
571 // Attach to Process
572 //
573 KeAttachProcess(&Process->Pcb);
574
575 //
576 // Allocate the PEB
577 //
578 Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
579 ASSERT(NT_SUCCESS(Status));
580
581 //
582 // Map NLS Tables
583 //
584 Status = MmMapViewOfSection(ExpNlsSectionPointer,
585 (PEPROCESS)Process,
586 &TableBase,
587 0,
588 0,
589 &SectionOffset,
590 &ViewSize,
591 ViewShare,
592 MEM_TOP_DOWN,
593 PAGE_READONLY);
594 if (!NT_SUCCESS(Status)) return Status;
595
596 //
597 // Use SEH in case we can't load the PEB
598 //
599 _SEH2_TRY
600 {
601 //
602 // Initialize the PEB
603 //
604 RtlZeroMemory(Peb, sizeof(PEB));
605
606 //
607 // Set up data
608 //
609 Peb->ImageBaseAddress = Process->SectionBaseAddress;
610 Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
611 Peb->Mutant = InitialPeb->Mutant;
612 Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
613
614 //
615 // NLS
616 //
617 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
618 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
619 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
620
621 //
622 // Default Version Data (could get changed below)
623 //
624 Peb->OSMajorVersion = NtMajorVersion;
625 Peb->OSMinorVersion = NtMinorVersion;
626 Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
627 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
628 Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
629
630 //
631 // Heap and Debug Data
632 //
633 Peb->NumberOfProcessors = KeNumberProcessors;
634 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
635 Peb->NtGlobalFlag = NtGlobalFlag;
636 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
637 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
638 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
639 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
640 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
641 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
642 */
643 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
644 Peb->ProcessHeaps = (PVOID*)(Peb + 1);
645
646 //
647 // Session ID
648 //
649 if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
650 }
651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
652 {
653 //
654 // Fail
655 //
656 KeDetachProcess();
657 _SEH2_YIELD(return _SEH2_GetExceptionCode());
658 }
659 _SEH2_END;
660
661 //
662 // Use SEH in case we can't load the image
663 //
664 _SEH2_TRY
665 {
666 //
667 // Get NT Headers
668 //
669 NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
670 Characteristics = NtHeaders->FileHeader.Characteristics;
671 }
672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
673 {
674 //
675 // Fail
676 //
677 KeDetachProcess();
678 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
679 }
680 _SEH2_END;
681
682 //
683 // Parse the headers
684 //
685 if (NtHeaders)
686 {
687 //
688 // Use SEH in case we can't load the headers
689 //
690 _SEH2_TRY
691 {
692 //
693 // Get the Image Config Data too
694 //
695 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
696 TRUE,
697 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
698 (PULONG)&ViewSize);
699 if (ImageConfigData)
700 {
701 //
702 // Probe it
703 //
704 ProbeForRead(ImageConfigData,
705 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
706 sizeof(ULONG));
707 }
708
709 //
710 // Write subsystem data
711 //
712 Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
713 Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
714 Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
715
716 //
717 // Check for version data
718 //
719 if (NtHeaders->OptionalHeader.Win32VersionValue)
720 {
721 //
722 // Extract values and write them
723 //
724 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
725 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
726 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
727 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
728 }
729
730 //
731 // Process the image config data overrides if specfied
732 //
733 if (ImageConfigData != NULL)
734 {
735 //
736 // Process CSD version override
737 //
738 if (ImageConfigData->CSDVersion)
739 {
740 //
741 // Set new data
742 //
743 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
744 }
745
746 //
747 // Process affinity mask ovverride
748 //
749 if (ImageConfigData->ProcessAffinityMask)
750 {
751 //
752 // Set new data
753 //
754 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
755 }
756 }
757
758 //
759 // Check if this is a UP image
760 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
761 {
762 //
763 // Force it to use CPU 0
764 //
765 Peb->ImageProcessAffinityMask = 0;
766 }
767 else
768 {
769 //
770 // Whatever was configured
771 //
772 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
773 }
774 }
775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
776 {
777 //
778 // Fail
779 //
780 KeDetachProcess();
781 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
782 }
783 _SEH2_END;
784 }
785
786 //
787 // Detach from the Process
788 //
789 KeDetachProcess();
790 *BasePeb = Peb;
791 return STATUS_SUCCESS;
792 }
793
794 NTSTATUS
795 NTAPI
796 MmCreateTeb(IN PEPROCESS Process,
797 IN PCLIENT_ID ClientId,
798 IN PINITIAL_TEB InitialTeb,
799 OUT PTEB *BaseTeb)
800 {
801 PTEB Teb;
802 NTSTATUS Status = STATUS_SUCCESS;
803 *BaseTeb = NULL;
804
805 //
806 // Attach to Target
807 //
808 KeAttachProcess(&Process->Pcb);
809
810 //
811 // Allocate the TEB
812 //
813 Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
814 ASSERT(NT_SUCCESS(Status));
815
816 //
817 // Use SEH in case we can't load the TEB
818 //
819 _SEH2_TRY
820 {
821 //
822 // Initialize the PEB
823 //
824 RtlZeroMemory(Teb, sizeof(TEB));
825
826 //
827 // Set TIB Data
828 //
829 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
830 Teb->NtTib.Self = (PNT_TIB)Teb;
831
832 //
833 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
834 //
835 Teb->NtTib.Version = 30 << 8;
836
837 //
838 // Set TEB Data
839 //
840 Teb->ClientId = *ClientId;
841 Teb->RealClientId = *ClientId;
842 Teb->ProcessEnvironmentBlock = Process->Peb;
843 Teb->CurrentLocale = PsDefaultThreadLocaleId;
844
845 //
846 // Check if we have a grandparent TEB
847 //
848 if ((InitialTeb->PreviousStackBase == NULL) &&
849 (InitialTeb->PreviousStackLimit == NULL))
850 {
851 //
852 // Use initial TEB values
853 //
854 Teb->NtTib.StackBase = InitialTeb->StackBase;
855 Teb->NtTib.StackLimit = InitialTeb->StackLimit;
856 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
857 }
858 else
859 {
860 //
861 // Use grandparent TEB values
862 //
863 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
864 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
865 }
866
867 //
868 // Initialize the static unicode string
869 //
870 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
871 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
872 }
873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
874 {
875 //
876 // Get error code
877 //
878 Status = _SEH2_GetExceptionCode();
879 }
880 _SEH2_END;
881
882 //
883 // Return
884 //
885 KeDetachProcess();
886 *BaseTeb = Teb;
887 return Status;
888 }
889
890 NTSTATUS
891 NTAPI
892 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
893 IN PEPROCESS ProcessClone OPTIONAL,
894 IN PVOID Section OPTIONAL,
895 IN OUT PULONG Flags,
896 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
897 {
898 NTSTATUS Status = STATUS_SUCCESS;
899 SIZE_T ViewSize = 0;
900 PVOID ImageBase = 0;
901 PROS_SECTION_OBJECT SectionObject = Section;
902 PMMPTE PointerPte;
903 KIRQL OldIrql;
904 PMMPDE PointerPde;
905 PFN_NUMBER PageFrameNumber;
906 UNICODE_STRING FileName;
907 PWCHAR Source;
908 PCHAR Destination;
909 USHORT Length = 0;
910
911 /* We should have a PDE */
912 ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
913 ASSERT(Process->PdeUpdateNeeded == FALSE);
914
915 /* Attach to the process */
916 KeAttachProcess(&Process->Pcb);
917
918 /* The address space should now been in phase 1 or 0 */
919 ASSERT(Process->AddressSpaceInitialized <= 1);
920 Process->AddressSpaceInitialized = 2;
921
922 /* Initialize the Addresss Space lock */
923 KeInitializeGuardedMutex(&Process->AddressCreationLock);
924 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
925
926 /* Initialize AVL tree */
927 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
928 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
929
930 /* Lock PFN database */
931 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
932
933 /* Setup the PFN for the PDE base of this process */
934 PointerPte = MiAddressToPte(PDE_BASE);
935 PageFrameNumber = PFN_FROM_PTE(PointerPte);
936 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
937
938 /* Do the same for hyperspace */
939 PointerPde = MiAddressToPde(HYPER_SPACE);
940 PageFrameNumber = PFN_FROM_PTE(PointerPde);
941 MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
942
943 /* Release PFN lock */
944 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
945
946 /* Lock the VAD, ARM3-owned ranges away */
947 MiRosTakeOverPebTebRanges(Process);
948
949 /* Check if there's a Section Object */
950 if (SectionObject)
951 {
952 /* Determine the image file name and save it to EPROCESS */
953 FileName = SectionObject->FileObject->FileName;
954 Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
955 if (FileName.Buffer)
956 {
957 /* Loop the file name*/
958 while (Source > FileName.Buffer)
959 {
960 /* Make sure this isn't a backslash */
961 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
962 {
963 /* If so, stop it here */
964 Source++;
965 break;
966 }
967 else
968 {
969 /* Otherwise, keep going */
970 Length++;
971 }
972 }
973 }
974
975 /* Copy the to the process and truncate it to 15 characters if necessary */
976 Destination = Process->ImageFileName;
977 Length = min(Length, sizeof(Process->ImageFileName) - 1);
978 while (Length--) *Destination++ = (UCHAR)*Source++;
979 *Destination = ANSI_NULL;
980
981 /* Check if caller wants an audit name */
982 if (AuditName)
983 {
984 /* Setup the audit name */
985 Status = SeInitializeProcessAuditName(SectionObject->FileObject,
986 FALSE,
987 AuditName);
988 if (!NT_SUCCESS(Status))
989 {
990 /* Fail */
991 KeDetachProcess();
992 return Status;
993 }
994 }
995
996 /* Map the section */
997 Status = MmMapViewOfSection(Section,
998 Process,
999 (PVOID*)&ImageBase,
1000 0,
1001 0,
1002 NULL,
1003 &ViewSize,
1004 0,
1005 MEM_COMMIT,
1006 PAGE_READWRITE);
1007
1008 /* Save the pointer */
1009 Process->SectionBaseAddress = ImageBase;
1010 }
1011
1012 /* Be nice and detach */
1013 KeDetachProcess();
1014
1015 /* Return status to caller */
1016 return Status;
1017 }
1018
1019 NTSTATUS
1020 NTAPI
1021 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
1022 IN PULONG_PTR DirectoryTableBase)
1023 {
1024 /* Share the directory base with the idle process */
1025 DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
1026 DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
1027
1028 /* Initialize the Addresss Space */
1029 KeInitializeGuardedMutex(&Process->AddressCreationLock);
1030 KeInitializeSpinLock(&Process->HyperSpaceLock);
1031 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
1032 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
1033 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
1034
1035 /* Done */
1036 Process->HasAddressSpace = TRUE;//??
1037 return STATUS_SUCCESS;
1038 }
1039
1040 NTSTATUS
1041 NTAPI
1042 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
1043 {
1044 /* Lock the VAD, ARM3-owned ranges away */
1045 MiRosTakeOverPebTebRanges(Process);
1046 return STATUS_SUCCESS;
1047 }
1048
1049 #ifdef _M_IX86
1050 /* FIXME: Evaluate ways to make this portable yet arch-specific */
1051 BOOLEAN
1052 NTAPI
1053 MmCreateProcessAddressSpace(IN ULONG MinWs,
1054 IN PEPROCESS Process,
1055 OUT PULONG_PTR DirectoryTableBase)
1056 {
1057 KIRQL OldIrql;
1058 PFN_NUMBER PdeIndex, HyperIndex;
1059 PMMPTE PointerPte;
1060 MMPTE TempPte, PdePte;
1061 ULONG PdeOffset;
1062 PMMPTE SystemTable;
1063
1064 /* No page colors yet */
1065 Process->NextPageColor = 0;
1066
1067 /* Setup the hyperspace lock */
1068 KeInitializeSpinLock(&Process->HyperSpaceLock);
1069
1070 /* Lock PFN database */
1071 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1072
1073 /* Get a page for the PDE */
1074 PdeIndex = MiRemoveAnyPage(0);
1075 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1076 MiZeroPhysicalPage(PdeIndex);
1077 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1078
1079 /* Get a page for hyperspace */
1080 HyperIndex = MiRemoveAnyPage(0);
1081 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1082 MiZeroPhysicalPage(HyperIndex);
1083
1084 /* Switch to phase 1 initialization */
1085 ASSERT(Process->AddressSpaceInitialized == 0);
1086 Process->AddressSpaceInitialized = 1;
1087
1088 /* Set the base directory pointers */
1089 DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
1090 DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
1091
1092 /* Make sure we don't already have a page directory setup */
1093 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
1094
1095 /* Insert us into the Mm process list */
1096 InsertTailList(&MmProcessList, &Process->MmProcessLinks);
1097
1098 /* Get a PTE to map the page directory */
1099 PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
1100 ASSERT(PointerPte != NULL);
1101
1102 /* Build it */
1103 MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
1104 PointerPte,
1105 MM_READWRITE,
1106 PdeIndex);
1107
1108 /* Set it dirty and map it */
1109 PdePte.u.Hard.Dirty = TRUE;
1110 MI_WRITE_VALID_PTE(PointerPte, PdePte);
1111
1112 /* Now get the page directory (which we'll double map, so call it a page table */
1113 SystemTable = MiPteToAddress(PointerPte);
1114
1115 /* Copy all the kernel mappings */
1116 PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
1117
1118 RtlCopyMemory(&SystemTable[PdeOffset],
1119 MiAddressToPde(MmSystemRangeStart),
1120 PAGE_SIZE - PdeOffset * sizeof(MMPTE));
1121
1122 /* Now write the PTE/PDE entry for hyperspace itself */
1123 TempPte = ValidKernelPte;
1124 TempPte.u.Hard.PageFrameNumber = HyperIndex;
1125 PdeOffset = MiGetPdeOffset(HYPER_SPACE);
1126 SystemTable[PdeOffset] = TempPte;
1127
1128 /* Sanity check */
1129 PdeOffset++;
1130 ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
1131
1132 /* Now do the x86 trick of making the PDE a page table itself */
1133 PdeOffset = MiGetPdeOffset(PTE_BASE);
1134 TempPte.u.Hard.PageFrameNumber = PdeIndex;
1135 SystemTable[PdeOffset] = TempPte;
1136
1137 /* Let go of the system PTE */
1138 MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
1139 return TRUE;
1140 }
1141 #endif
1142
1143 VOID
1144 NTAPI
1145 MmCleanProcessAddressSpace(IN PEPROCESS Process)
1146 {
1147 PMMVAD Vad;
1148 PMM_AVL_TABLE VadTree;
1149 PETHREAD Thread = PsGetCurrentThread();
1150
1151 /* Lock the process address space from changes */
1152 MmLockAddressSpace(&Process->Vm);
1153
1154 /* Enumerate the VADs */
1155 VadTree = &Process->VadRoot;
1156 DPRINT("Cleaning up VADs: %d\n", VadTree->NumberGenericTableElements);
1157 while (VadTree->NumberGenericTableElements)
1158 {
1159 /* Grab the current VAD */
1160 Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
1161
1162 /* Lock the working set */
1163 MiLockProcessWorkingSet(Process, Thread);
1164
1165 /* Remove this VAD from the tree */
1166 ASSERT(VadTree->NumberGenericTableElements >= 1);
1167 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
1168 DPRINT("Moving on: %d\n", VadTree->NumberGenericTableElements);
1169
1170 /* Only PEB/TEB VADs supported for now */
1171 ASSERT(Vad->u.VadFlags.PrivateMemory == 1);
1172 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1173
1174 /* Release the working set */
1175 MiUnlockProcessWorkingSet(Process, Thread);
1176
1177 /* Free the VAD memory */
1178 ExFreePool(Vad);
1179 }
1180
1181 /* Release the address space */
1182 MmUnlockAddressSpace(&Process->Vm);
1183 }
1184
1185 /* SYSTEM CALLS ***************************************************************/
1186
1187 NTSTATUS
1188 NTAPI
1189 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
1190 IN OUT PULONG_PTR NumberOfPages,
1191 IN OUT PULONG_PTR UserPfnArray)
1192 {
1193 UNIMPLEMENTED;
1194 return STATUS_NOT_IMPLEMENTED;
1195 }
1196
1197 NTSTATUS
1198 NTAPI
1199 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
1200 IN ULONG_PTR NumberOfPages,
1201 IN OUT PULONG_PTR UserPfnArray)
1202 {
1203 UNIMPLEMENTED;
1204 return STATUS_NOT_IMPLEMENTED;
1205 }
1206
1207 NTSTATUS
1208 NTAPI
1209 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
1210 IN ULONG_PTR NumberOfPages,
1211 IN OUT PULONG_PTR UserPfnArray)
1212 {
1213 UNIMPLEMENTED;
1214 return STATUS_NOT_IMPLEMENTED;
1215 }
1216
1217 NTSTATUS
1218 NTAPI
1219 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
1220 IN OUT PULONG_PTR NumberOfPages,
1221 IN OUT PULONG_PTR UserPfnArray)
1222 {
1223 UNIMPLEMENTED;
1224 return STATUS_NOT_IMPLEMENTED;
1225 }
1226
1227 /* EOF */