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