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