2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/process.c
5 * PURPOSE: Memory functions related to Processes
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 extern ULONG NtMajorVersion
;
17 extern ULONG NtMinorVersion
;
18 extern ULONG CmNtCSDVersion
;
19 extern ULONG NtBuildNumber
;
20 extern MM_SYSTEMSIZE MmSystemSize
;
22 #define MM_HIGHEST_VAD_ADDRESS \
23 (PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
25 /* FUNCTIONS *****************************************************************/
29 MmSetMemoryPriorityProcess(IN PEPROCESS Process
,
30 IN UCHAR MemoryPriority
)
34 /* Check if we have less then 16MB of Physical Memory */
35 if ((MmSystemSize
== MmSmallSystem
) &&
36 (MmStats
.NrTotalPages
< ((15 * 1024 * 1024) / PAGE_SIZE
)))
38 /* Always use background priority */
42 /* Save the old priority and update it */
43 OldPriority
= (UCHAR
)Process
->Vm
.Flags
.MemoryPriority
;
44 Process
->Vm
.Flags
.MemoryPriority
= MemoryPriority
;
46 /* Return the old priority */
52 MmGetSessionLocaleId(VOID
)
57 /* Get the current process */
58 Process
= PsGetCurrentProcess();
60 /* Check if it's the Session Leader */
61 if (Process
->Vm
.Flags
.SessionLeader
)
63 /* Make sure it has a valid Session */
66 /* Get the Locale ID */
68 return ((PMM_SESSION_SPACE
)Process
->Session
)->LocaleId
;
73 /* Not a session leader, return the default */
74 return PsDefaultThreadLocaleId
;
79 MiCreatePebOrTeb(PEPROCESS Process
,
83 PMADDRESS_SPACE ProcessAddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
84 PMEMORY_AREA MemoryArea
;
85 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
86 PVOID AllocatedBase
= BaseAddress
;
87 BoundaryAddressMultiple
.QuadPart
= 0;
89 /* Acquire the Lock */
90 MmLockAddressSpace(ProcessAddressSpace
);
93 * Create a Peb or Teb.
94 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
95 * is that a PEB allocation should never fail since the address is free,
96 * while TEB allocation can fail, and we should simply try the address
97 * below. Is there a nicer way of doing this automagically? (ie: findning)
98 * a gap region? -- Alex
101 DPRINT("Trying to allocate: %x\n", AllocatedBase
);
102 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
103 MEMORY_AREA_PEB_OR_TEB
,
110 BoundaryAddressMultiple
);
111 AllocatedBase
= RVA(AllocatedBase
, -PAGE_SIZE
);
112 } while (Status
!= STATUS_SUCCESS
);
114 /* Initialize the Region */
115 MmInitializeRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
120 /* Reserve the pages */
121 MmReserveSwapPages(PAGE_SIZE
);
123 /* Unlock Address Space */
124 DPRINT("Returning\n");
125 MmUnlockAddressSpace(ProcessAddressSpace
);
126 return RVA(AllocatedBase
, PAGE_SIZE
);
130 MiFreeStackPage(PVOID Context
,
131 MEMORY_AREA
* MemoryArea
,
137 ASSERT(SwapEntry
== 0);
138 if (Page
) MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
143 MmDeleteKernelStack(PVOID Stack
,
146 /* Lock the Address Space */
147 MmLockAddressSpace(MmGetKernelAddressSpace());
149 /* Delete the Stack */
150 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
155 /* Unlock the Address Space */
156 MmUnlockAddressSpace(MmGetKernelAddressSpace());
161 MmDeleteTeb(PEPROCESS Process
,
164 PMADDRESS_SPACE ProcessAddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
165 PMEMORY_AREA MemoryArea
;
167 /* Lock the Address Space */
168 MmLockAddressSpace(ProcessAddressSpace
);
170 MemoryArea
= MmLocateMemoryAreaByAddress(ProcessAddressSpace
, (PVOID
)Teb
);
174 MmFreeVirtualMemory(Process
, MemoryArea
);
177 /* Unlock the Address Space */
178 MmUnlockAddressSpace(ProcessAddressSpace
);
183 MmCreateKernelStack(BOOLEAN GuiStack
,
186 PMEMORY_AREA StackArea
;
188 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
189 ULONG StackSize
= GuiStack
? KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
;
190 PFN_TYPE Page
[KERNEL_LARGE_STACK_SIZE
/ PAGE_SIZE
];
191 PVOID KernelStack
= NULL
;
194 /* Initialize the Boundary Address */
195 BoundaryAddressMultiple
.QuadPart
= 0;
197 /* Lock the Kernel Address Space */
198 MmLockAddressSpace(MmGetKernelAddressSpace());
200 /* Create a MAREA for the Kernel Stack */
201 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
202 MEMORY_AREA_KERNEL_STACK
,
209 BoundaryAddressMultiple
);
211 /* Unlock the Address Space */
212 MmUnlockAddressSpace(MmGetKernelAddressSpace());
214 /* Check for Success */
215 if (!NT_SUCCESS(Status
))
217 DPRINT1("Failed to create thread stack\n");
222 * Mark the Stack in use.
223 * Note: Currently we mark all 60KB in use for a GUI Thread.
224 * We should only do this inside MmGrowKernelStack. TODO!
226 for (i
= 0; i
< (StackSize
/ PAGE_SIZE
); i
++)
228 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
231 /* Create a Virtual Mapping for it */
232 Status
= MmCreateVirtualMapping(NULL
,
236 StackSize
/ PAGE_SIZE
);
238 /* Check for success */
239 if (!NT_SUCCESS(Status
))
241 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
245 /* Return the stack base */
246 return (PVOID
)((ULONG_PTR
)KernelStack
+
247 (GuiStack
? KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
));
255 MmGrowKernelStack(PVOID StackPointer
)
257 PETHREAD Thread
= PsGetCurrentThread();
259 /* Make sure we have reserved space for our grow */
260 ASSERT(((PCHAR
)Thread
->Tcb
.StackBase
- (PCHAR
)Thread
->Tcb
.StackLimit
) <=
261 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
264 * We'll give you three more pages.
265 * NOTE: See note in MmCreateKernelStack. These pages are already being reserved.
266 * It would be more efficient to only grow them (commit them) here.
268 Thread
->Tcb
.StackLimit
-= KERNEL_STACK_SIZE
;
271 return STATUS_SUCCESS
;
276 MmCreatePeb(PEPROCESS Process
)
279 LARGE_INTEGER SectionOffset
;
281 PVOID TableBase
= NULL
;
282 PIMAGE_NT_HEADERS NtHeaders
;
283 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
285 KAFFINITY ProcessAffinityMask
= 0;
286 SectionOffset
.QuadPart
= (ULONGLONG
)0;
287 DPRINT("MmCreatePeb\n");
289 /* Allocate the PEB */
290 Peb
= MiCreatePebOrTeb(Process
,
291 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
292 ASSERT(Peb
== (PVOID
)0x7FFDF000);
295 DPRINT("Mapping NLS\n");
296 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
306 if (!NT_SUCCESS(Status
))
308 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
311 DPRINT("TableBase %p ViewSize %lx\n", TableBase
, ViewSize
);
313 /* Attach to Process */
314 KeAttachProcess(&Process
->Pcb
);
316 /* Initialize the PEB */
317 DPRINT("Allocated: %x\n", Peb
);
318 RtlZeroMemory(Peb
, sizeof(PEB
));
321 DPRINT("Setting up PEB\n");
322 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
323 Peb
->InheritedAddressSpace
= 0;
327 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
328 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
329 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
331 /* Default Version Data (could get changed below) */
332 Peb
->OSMajorVersion
= NtMajorVersion
;
333 Peb
->OSMinorVersion
= NtMinorVersion
;
334 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
335 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
336 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
338 /* Heap and Debug Data */
339 Peb
->NumberOfProcessors
= KeNumberProcessors
;
340 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
341 Peb
->NtGlobalFlag
= NtGlobalFlag
;
342 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
343 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
344 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
345 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
346 Peb
->NumberOfHeaps
= 0;
347 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
348 Peb
->ProcessHeaps
= (PVOID
*)Peb
+ 1;
351 if ((NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
)))
353 /* Write subsystem data */
354 Peb
->ImageSubSystem
= NtHeaders
->OptionalHeader
.Subsystem
;
355 Peb
->ImageSubSystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
356 Peb
->ImageSubSystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
358 /* Write Version Data */
359 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
361 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
362 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
363 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
365 /* Set the Platform ID */
366 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
369 /* Check if the image is not safe for SMP */
370 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
372 /* FIXME: Choose one randomly */
373 Peb
->ImageProcessAffinityMask
= 1;
377 /* Use affinity from Image Header */
378 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
383 /* Get the Image Config Data too */
384 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
386 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
389 ProbeForRead(ImageConfigData
,
390 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
393 /* Process the image config data overrides if specfied. */
394 if (ImageConfigData
!= NULL
)
396 if (ImageConfigData
->CSDVersion
)
398 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
400 if (ImageConfigData
->ProcessAffinityMask
)
402 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
408 Status
= _SEH_GetExceptionCode();
414 Peb
->SessionId
= Process
->Session
;
417 /* Detach from the Process */
420 DPRINT("MmCreatePeb: Peb created at %p\n", Peb
);
426 MmCreateTeb(PEPROCESS Process
,
428 PINITIAL_TEB InitialTeb
)
431 BOOLEAN Attached
= FALSE
;
433 /* Attach to the process */
434 DPRINT("MmCreateTeb\n");
435 if (Process
!= PsGetCurrentProcess())
437 /* Attach to Target */
438 KeAttachProcess(&Process
->Pcb
);
442 /* Allocate the TEB */
443 Teb
= MiCreatePebOrTeb(Process
,
444 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
446 /* Initialize the PEB */
447 RtlZeroMemory(Teb
, sizeof(TEB
));
450 Teb
->Tib
.ExceptionList
= (PVOID
)0xFFFFFFFF;
451 Teb
->Tib
.Version
= 1;
452 Teb
->Tib
.Self
= (PNT_TIB
)Teb
;
455 Teb
->Cid
= *ClientId
;
456 Teb
->RealClientId
= *ClientId
;
457 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
458 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
460 /* Store stack information from InitialTeb */
461 if(InitialTeb
!= NULL
)
463 Teb
->Tib
.StackBase
= InitialTeb
->StackBase
;
464 Teb
->Tib
.StackLimit
= InitialTeb
->StackLimit
;
465 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
468 /* Initialize the static unicode string */
469 Teb
->StaticUnicodeString
.Length
= 0;
470 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
471 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
473 /* Return TEB Address */
474 DPRINT("Allocated: %x\n", Teb
);
475 if (Attached
) KeDetachProcess();
481 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
484 PMEMORY_AREA MemoryArea
;
485 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
487 PMADDRESS_SPACE ProcessAddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
488 BoundaryAddressMultiple
.QuadPart
= 0;
490 /* Create the shared data page */
491 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
492 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
493 MEMORY_AREA_SHARED_DATA
,
500 BoundaryAddressMultiple
);
506 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
507 IN PEPROCESS ProcessClone OPTIONAL
,
508 IN PVOID Section OPTIONAL
,
510 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
513 PMADDRESS_SPACE ProcessAddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
515 PMEMORY_AREA MemoryArea
;
516 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
519 PROS_SECTION_OBJECT SectionObject
= Section
;
520 BoundaryAddressMultiple
.QuadPart
= 0;
522 /* Initialize the Addresss Space */
523 MmInitializeAddressSpace(Process
, ProcessAddressSpace
);
525 /* Acquire the Lock */
526 MmLockAddressSpace(ProcessAddressSpace
);
528 /* Protect the highest 64KB of the process address space */
529 BaseAddress
= (PVOID
)MmUserProbeAddress
;
530 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
531 MEMORY_AREA_NO_ACCESS
,
538 BoundaryAddressMultiple
);
539 if (!NT_SUCCESS(Status
))
541 DPRINT1("Failed to protect last 64KB\n");
545 /* Protect the 60KB above the shared user page */
546 BaseAddress
= (char*)USER_SHARED_DATA
+ PAGE_SIZE
;
547 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
548 MEMORY_AREA_NO_ACCESS
,
555 BoundaryAddressMultiple
);
556 if (!NT_SUCCESS(Status
))
558 DPRINT1("Failed to protect the memory above the shared user page\n");
562 /* Create the shared data page */
563 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
564 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
565 MEMORY_AREA_SHARED_DATA
,
572 BoundaryAddressMultiple
);
573 if (!NT_SUCCESS(Status
))
575 DPRINT1("Failed to create Shared User Data\n");
579 /* The process now has an address space */
580 Process
->HasAddressSpace
= TRUE
;
582 /* Check if there's a Section Object */
585 UNICODE_STRING FileName
;
590 /* Unlock the Address Space */
591 DPRINT("Unlocking\n");
592 MmUnlockAddressSpace(ProcessAddressSpace
);
594 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
595 SectionObject
, Process
, &ImageBase
);
596 Status
= MmMapViewOfSection(Section
,
606 if (!NT_SUCCESS(Status
))
608 DPRINT1("Failed to map process Image\n");
612 /* Save the pointer */
613 Process
->SectionBaseAddress
= ImageBase
;
615 /* Determine the image file name and save it to EPROCESS */
616 DPRINT("Getting Image name\n");
617 FileName
= SectionObject
->FileObject
->FileName
;
618 szSrc
= (PWCHAR
)(FileName
.Buffer
+ FileName
.Length
);
619 while (szSrc
>= FileName
.Buffer
)
621 /* Make sure this isn't a backslash */
622 if (*--szSrc
== OBJ_NAME_PATH_SEPARATOR
)
624 /* If so, stop it here */
630 /* Otherwise, keep going */
635 /* Copy the to the process and truncate it to 15 characters if necessary */
636 szDest
= Process
->ImageFileName
;
637 lnFName
= min(lnFName
, sizeof(Process
->ImageFileName
) - 1);
638 while (lnFName
--) *szDest
++ = (UCHAR
)*szSrc
++;
639 *szDest
= UNICODE_NULL
;
641 /* Check if caller wants an audit name */
644 /* Setup the audit name */
645 SeInitializeProcessAuditName(SectionObject
->FileObject
,
650 /* Return status to caller */
655 /* Unlock the Address Space */
656 DPRINT("Unlocking\n");
657 MmUnlockAddressSpace(ProcessAddressSpace
);
659 /* Return status to caller */
665 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
667 /* FIXME: Add part of MmDeleteProcessAddressSpace here */
672 MmDeleteProcessAddressSpace(PEPROCESS Process
)
675 PMEMORY_AREA MemoryArea
;
677 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process
,
678 Process
->ImageFileName
);
680 MmLockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
682 while ((MemoryArea
= ((PMADDRESS_SPACE
)&Process
->VadRoot
)->MemoryAreaRoot
) != NULL
)
684 switch (MemoryArea
->Type
)
686 case MEMORY_AREA_SECTION_VIEW
:
687 Address
= (PVOID
)MemoryArea
->StartingAddress
;
688 MmUnlockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
689 MmUnmapViewOfSection(Process
, Address
);
690 MmLockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
693 case MEMORY_AREA_VIRTUAL_MEMORY
:
694 case MEMORY_AREA_PEB_OR_TEB
:
695 MmFreeVirtualMemory(Process
, MemoryArea
);
698 case MEMORY_AREA_SHARED_DATA
:
699 case MEMORY_AREA_NO_ACCESS
:
700 MmFreeMemoryArea((PMADDRESS_SPACE
)&Process
->VadRoot
,
706 case MEMORY_AREA_MDL_MAPPING
:
707 KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES
);
715 Mmi386ReleaseMmInfo(Process
);
717 MmUnlockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
718 MmDestroyAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
720 DPRINT("Finished MmReleaseMmInfo()\n");
721 return(STATUS_SUCCESS
);