Sync with trunk (r48123)
[reactos.git] / ntoskrnl / mm / ARM3 / procsup.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/procsup.c
5 * PURPOSE: ARM Memory Manager Process Related Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::PROCSUP"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 extern MM_SYSTEMSIZE MmSystemSize;
20
21 PVOID
22 NTAPI
23 MiCreatePebOrTeb(PEPROCESS Process,
24 PVOID BaseAddress);
25
26 /* PRIVATE FUNCTIONS **********************************************************/
27
28 VOID
29 NTAPI
30 MmDeleteKernelStack(IN PVOID StackBase,
31 IN BOOLEAN GuiStack)
32 {
33 PMMPTE PointerPte;
34 PFN_NUMBER StackPages, PageFrameNumber;//, PageTableFrameNumber;
35 PMMPFN Pfn1;//, Pfn2;
36 ULONG i;
37 KIRQL OldIrql;
38
39 //
40 // This should be the guard page, so decrement by one
41 //
42 PointerPte = MiAddressToPte(StackBase);
43 PointerPte--;
44
45 //
46 // Calculate pages used
47 //
48 StackPages = BYTES_TO_PAGES(GuiStack ?
49 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
50
51 /* Acquire the PFN lock */
52 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
53
54 //
55 // Loop them
56 //
57 for (i = 0; i < StackPages; i++)
58 {
59 //
60 // Check if this is a valid PTE
61 //
62 if (PointerPte->u.Hard.Valid == 1)
63 {
64 /* Get the PTE's page */
65 PageFrameNumber = PFN_FROM_PTE(PointerPte);
66 Pfn1 = MiGetPfnEntry(PageFrameNumber);
67 #if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
68 /* Now get the page of the page table mapping it */
69 PageTableFrameNumber = Pfn1->u4.PteFrame;
70 Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
71
72 /* Remove a shared reference, since the page is going away */
73 MiDecrementShareCount(Pfn2, PageTableFrameNumber);
74 #endif
75 /* Set the special pending delete marker */
76 Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
77
78 /* And now delete the actual stack page */
79 MiDecrementShareCount(Pfn1, PageFrameNumber);
80 }
81
82 //
83 // Next one
84 //
85 PointerPte--;
86 }
87
88 //
89 // We should be at the guard page now
90 //
91 ASSERT(PointerPte->u.Hard.Valid == 0);
92
93 /* Release the PFN lock */
94 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
95
96 //
97 // Release the PTEs
98 //
99 MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace);
100 }
101
102 PVOID
103 NTAPI
104 MmCreateKernelStack(IN BOOLEAN GuiStack,
105 IN UCHAR Node)
106 {
107 PFN_NUMBER StackPtes, StackPages;
108 PMMPTE PointerPte, StackPte;
109 PVOID BaseAddress;
110 MMPTE TempPte, InvalidPte;
111 KIRQL OldIrql;
112 PFN_NUMBER PageFrameIndex;
113 ULONG i;
114
115 //
116 // Calculate pages needed
117 //
118 if (GuiStack)
119 {
120 //
121 // We'll allocate 64KB stack, but only commit 12K
122 //
123 StackPtes = BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE);
124 StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT);
125
126 }
127 else
128 {
129 //
130 // We'll allocate 12K and that's it
131 //
132 StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE);
133 StackPages = StackPtes;
134 }
135
136 //
137 // Reserve stack pages, plus a guard page
138 //
139 StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace);
140 if (!StackPte) return NULL;
141
142 //
143 // Get the stack address
144 //
145 BaseAddress = MiPteToAddress(StackPte + StackPtes + 1);
146
147 //
148 // Select the right PTE address where we actually start committing pages
149 //
150 PointerPte = StackPte;
151 if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE -
152 KERNEL_LARGE_STACK_COMMIT);
153
154
155 /* Setup the temporary invalid PTE */
156 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
157
158 /* Setup the template stack PTE */
159 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte + 1, MM_READWRITE, 0);
160
161 //
162 // Acquire the PFN DB lock
163 //
164 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
165
166 //
167 // Loop each stack page
168 //
169 for (i = 0; i < StackPages; i++)
170 {
171 //
172 // Next PTE
173 //
174 PointerPte++;
175
176 /* Get a page and write the current invalid PTE */
177 PageFrameIndex = MiRemoveAnyPage(0);
178 MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
179
180 /* Initialize the PFN entry for this page */
181 MiInitializePfn(PageFrameIndex, PointerPte, 1);
182
183 /* Write the valid PTE */
184 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
185 MI_WRITE_VALID_PTE(PointerPte, TempPte);
186 }
187
188 // Bug #4835
189 (VOID)InterlockedExchangeAddUL(&MiMemoryConsumers[MC_NPPOOL].PagesUsed, StackPages);
190
191 //
192 // Release the PFN lock
193 //
194 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
195
196 //
197 // Return the stack address
198 //
199 return BaseAddress;
200 }
201
202 NTSTATUS
203 NTAPI
204 MmGrowKernelStackEx(IN PVOID StackPointer,
205 IN ULONG GrowSize)
206 {
207 PKTHREAD Thread = KeGetCurrentThread();
208 PMMPTE LimitPte, NewLimitPte, LastPte;
209 PFN_NUMBER StackPages;
210 KIRQL OldIrql;
211 MMPTE TempPte, InvalidPte;
212 PFN_NUMBER PageFrameIndex;
213
214 //
215 // Make sure the stack did not overflow
216 //
217 ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
218 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
219
220 //
221 // Get the current stack limit
222 //
223 LimitPte = MiAddressToPte(Thread->StackLimit);
224 ASSERT(LimitPte->u.Hard.Valid == 1);
225
226 //
227 // Get the new one and make sure this isn't a retarded request
228 //
229 NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
230 if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
231
232 //
233 // Now make sure you're not going past the reserved space
234 //
235 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
236 KERNEL_LARGE_STACK_SIZE));
237 if (NewLimitPte < LastPte)
238 {
239 //
240 // Sorry!
241 //
242 DPRINT1("Thread wants too much stack\n");
243 return STATUS_STACK_OVERFLOW;
244 }
245
246 //
247 // Calculate the number of new pages
248 //
249 LimitPte--;
250 StackPages = (LimitPte - NewLimitPte + 1);
251
252 /* Setup the temporary invalid PTE */
253 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
254
255 //
256 // Acquire the PFN DB lock
257 //
258 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
259
260 //
261 // Loop each stack page
262 //
263 while (LimitPte >= NewLimitPte)
264 {
265 /* Get a page and write the current invalid PTE */
266 PageFrameIndex = MiRemoveAnyPage(0);
267 MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
268
269 /* Initialize the PFN entry for this page */
270 MiInitializePfn(PageFrameIndex, LimitPte, 1);
271
272 /* Setup the template stack PTE */
273 MI_MAKE_HARDWARE_PTE(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
274
275 /* Write the valid PTE */
276 MI_WRITE_VALID_PTE(LimitPte--, TempPte);
277 }
278
279 //
280 // Release the PFN lock
281 //
282 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
283
284 //
285 // Set the new limit
286 //
287 Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
288 return STATUS_SUCCESS;
289 }
290
291 NTSTATUS
292 NTAPI
293 MmGrowKernelStack(IN PVOID StackPointer)
294 {
295 //
296 // Call the extended version
297 //
298 return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
299 }
300
301 NTSTATUS
302 NTAPI
303 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
304 IN UCHAR MemoryPriority)
305 {
306 UCHAR OldPriority;
307
308 //
309 // Check if we have less then 16MB of Physical Memory
310 //
311 if ((MmSystemSize == MmSmallSystem) &&
312 (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
313 {
314 //
315 // Always use background priority
316 //
317 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
318 }
319
320 //
321 // Save the old priority and update it
322 //
323 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
324 Process->Vm.Flags.MemoryPriority = MemoryPriority;
325
326 //
327 // Return the old priority
328 //
329 return OldPriority;
330 }
331
332 LCID
333 NTAPI
334 MmGetSessionLocaleId(VOID)
335 {
336 PEPROCESS Process;
337 PAGED_CODE();
338
339 //
340 // Get the current process
341 //
342 Process = PsGetCurrentProcess();
343
344 //
345 // Check if it's the Session Leader
346 //
347 if (Process->Vm.Flags.SessionLeader)
348 {
349 //
350 // Make sure it has a valid Session
351 //
352 if (Process->Session)
353 {
354 //
355 // Get the Locale ID
356 //
357 #if ROS_HAS_SESSIONS
358 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
359 #endif
360 }
361 }
362
363 //
364 // Not a session leader, return the default
365 //
366 return PsDefaultThreadLocaleId;
367 }
368
369 NTSTATUS
370 NTAPI
371 MmCreatePeb(IN PEPROCESS Process,
372 IN PINITIAL_PEB InitialPeb,
373 OUT PPEB *BasePeb)
374 {
375 PPEB Peb = NULL;
376 LARGE_INTEGER SectionOffset;
377 SIZE_T ViewSize = 0;
378 PVOID TableBase = NULL;
379 PIMAGE_NT_HEADERS NtHeaders;
380 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
381 NTSTATUS Status;
382 USHORT Characteristics;
383 KAFFINITY ProcessAffinityMask = 0;
384 SectionOffset.QuadPart = (ULONGLONG)0;
385 *BasePeb = NULL;
386
387 //
388 // Attach to Process
389 //
390 KeAttachProcess(&Process->Pcb);
391
392 //
393 // Allocate the PEB
394 //
395 Peb = MiCreatePebOrTeb(Process,
396 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
397 ASSERT(Peb == (PVOID)0x7FFDF000);
398
399 //
400 // Map NLS Tables
401 //
402 Status = MmMapViewOfSection(ExpNlsSectionPointer,
403 (PEPROCESS)Process,
404 &TableBase,
405 0,
406 0,
407 &SectionOffset,
408 &ViewSize,
409 ViewShare,
410 MEM_TOP_DOWN,
411 PAGE_READONLY);
412 if (!NT_SUCCESS(Status)) return Status;
413
414 //
415 // Use SEH in case we can't load the PEB
416 //
417 _SEH2_TRY
418 {
419 //
420 // Initialize the PEB
421 //
422 RtlZeroMemory(Peb, sizeof(PEB));
423
424 //
425 // Set up data
426 //
427 Peb->ImageBaseAddress = Process->SectionBaseAddress;
428 Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
429 Peb->Mutant = InitialPeb->Mutant;
430 Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
431
432 //
433 // NLS
434 //
435 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
436 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
437 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
438
439 //
440 // Default Version Data (could get changed below)
441 //
442 Peb->OSMajorVersion = NtMajorVersion;
443 Peb->OSMinorVersion = NtMinorVersion;
444 Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
445 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
446 Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
447
448 //
449 // Heap and Debug Data
450 //
451 Peb->NumberOfProcessors = KeNumberProcessors;
452 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
453 Peb->NtGlobalFlag = NtGlobalFlag;
454 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
455 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
456 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
457 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
458 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
459 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
460 */
461 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
462 Peb->ProcessHeaps = (PVOID*)(Peb + 1);
463
464 //
465 // Session ID
466 //
467 if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
468 }
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
470 {
471 //
472 // Fail
473 //
474 KeDetachProcess();
475 _SEH2_YIELD(return _SEH2_GetExceptionCode());
476 }
477 _SEH2_END;
478
479 //
480 // Use SEH in case we can't load the image
481 //
482 _SEH2_TRY
483 {
484 //
485 // Get NT Headers
486 //
487 NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
488 Characteristics = NtHeaders->FileHeader.Characteristics;
489 }
490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
491 {
492 //
493 // Fail
494 //
495 KeDetachProcess();
496 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
497 }
498 _SEH2_END;
499
500 //
501 // Parse the headers
502 //
503 if (NtHeaders)
504 {
505 //
506 // Use SEH in case we can't load the headers
507 //
508 _SEH2_TRY
509 {
510 //
511 // Get the Image Config Data too
512 //
513 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
514 TRUE,
515 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
516 (PULONG)&ViewSize);
517 if (ImageConfigData)
518 {
519 //
520 // Probe it
521 //
522 ProbeForRead(ImageConfigData,
523 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
524 sizeof(ULONG));
525 }
526
527 //
528 // Write subsystem data
529 //
530 Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
531 Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
532 Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
533
534 //
535 // Check for version data
536 //
537 if (NtHeaders->OptionalHeader.Win32VersionValue)
538 {
539 //
540 // Extract values and write them
541 //
542 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
543 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
544 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
545 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
546 }
547
548 //
549 // Process the image config data overrides if specfied
550 //
551 if (ImageConfigData != NULL)
552 {
553 //
554 // Process CSD version override
555 //
556 if (ImageConfigData->CSDVersion)
557 {
558 //
559 // Set new data
560 //
561 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
562 }
563
564 //
565 // Process affinity mask ovverride
566 //
567 if (ImageConfigData->ProcessAffinityMask)
568 {
569 //
570 // Set new data
571 //
572 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
573 }
574 }
575
576 //
577 // Check if this is a UP image
578 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
579 {
580 //
581 // Force it to use CPU 0
582 //
583 Peb->ImageProcessAffinityMask = 0;
584 }
585 else
586 {
587 //
588 // Whatever was configured
589 //
590 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
591 }
592 }
593 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
594 {
595 //
596 // Fail
597 //
598 KeDetachProcess();
599 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
600 }
601 _SEH2_END;
602 }
603
604 //
605 // Detach from the Process
606 //
607 KeDetachProcess();
608 *BasePeb = Peb;
609 return STATUS_SUCCESS;
610 }
611
612 NTSTATUS
613 NTAPI
614 MmCreateTeb(IN PEPROCESS Process,
615 IN PCLIENT_ID ClientId,
616 IN PINITIAL_TEB InitialTeb,
617 OUT PTEB *BaseTeb)
618 {
619 PTEB Teb;
620 NTSTATUS Status = STATUS_SUCCESS;
621 *BaseTeb = NULL;
622
623 //
624 // Attach to Target
625 //
626 KeAttachProcess(&Process->Pcb);
627
628 //
629 // Allocate the TEB
630 //
631 Teb = MiCreatePebOrTeb(Process,
632 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
633 if (!Teb) return STATUS_INSUFFICIENT_RESOURCES;
634
635 //
636 // Use SEH in case we can't load the TEB
637 //
638 _SEH2_TRY
639 {
640 //
641 // Initialize the PEB
642 //
643 RtlZeroMemory(Teb, sizeof(TEB));
644
645 //
646 // Set TIB Data
647 //
648 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
649 Teb->NtTib.Self = (PNT_TIB)Teb;
650
651 //
652 // Identify this as an OS/2 V3.0 ("Cruiser") TIB
653 //
654 Teb->NtTib.Version = 30 << 8;
655
656 //
657 // Set TEB Data
658 //
659 Teb->ClientId = *ClientId;
660 Teb->RealClientId = *ClientId;
661 Teb->ProcessEnvironmentBlock = Process->Peb;
662 Teb->CurrentLocale = PsDefaultThreadLocaleId;
663
664 //
665 // Check if we have a grandparent TEB
666 //
667 if ((InitialTeb->PreviousStackBase == NULL) &&
668 (InitialTeb->PreviousStackLimit == NULL))
669 {
670 //
671 // Use initial TEB values
672 //
673 Teb->NtTib.StackBase = InitialTeb->StackBase;
674 Teb->NtTib.StackLimit = InitialTeb->StackLimit;
675 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
676 }
677 else
678 {
679 //
680 // Use grandparent TEB values
681 //
682 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
683 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
684 }
685
686 //
687 // Initialize the static unicode string
688 //
689 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
690 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
691 }
692 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
693 {
694 //
695 // Get error code
696 //
697 Status = _SEH2_GetExceptionCode();
698 }
699 _SEH2_END;
700
701 //
702 // Return
703 //
704 KeDetachProcess();
705 *BaseTeb = Teb;
706 return Status;
707 }
708
709 /* SYSTEM CALLS ***************************************************************/
710
711 NTSTATUS
712 NTAPI
713 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
714 IN OUT PULONG_PTR NumberOfPages,
715 IN OUT PULONG_PTR UserPfnArray)
716 {
717 UNIMPLEMENTED;
718 return STATUS_NOT_IMPLEMENTED;
719 }
720
721 NTSTATUS
722 NTAPI
723 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
724 IN ULONG_PTR NumberOfPages,
725 IN OUT PULONG_PTR UserPfnArray)
726 {
727 UNIMPLEMENTED;
728 return STATUS_NOT_IMPLEMENTED;
729 }
730
731 NTSTATUS
732 NTAPI
733 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
734 IN ULONG_PTR NumberOfPages,
735 IN OUT PULONG_PTR UserPfnArray)
736 {
737 UNIMPLEMENTED;
738 return STATUS_NOT_IMPLEMENTED;
739 }
740
741 NTSTATUS
742 NTAPI
743 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
744 IN OUT PULONG_PTR NumberOfPages,
745 IN OUT PULONG_PTR UserPfnArray)
746 {
747 UNIMPLEMENTED;
748 return STATUS_NOT_IMPLEMENTED;
749 }
750
751 /* EOF */