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