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