2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/procsup.c
5 * PURPOSE: Memory functions related to Processes
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
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 PMMSUPPORT ProcessAddressSpace
= &Process
->Vm
;
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
);
131 MmDeleteTeb(PEPROCESS Process
,
134 PMMSUPPORT ProcessAddressSpace
= &Process
->Vm
;
135 PMEMORY_AREA MemoryArea
;
137 /* Lock the Address Space */
138 MmLockAddressSpace(ProcessAddressSpace
);
140 MemoryArea
= MmLocateMemoryAreaByAddress(ProcessAddressSpace
, (PVOID
)Teb
);
144 MmFreeVirtualMemory(Process
, MemoryArea
);
147 /* Unlock the Address Space */
148 MmUnlockAddressSpace(ProcessAddressSpace
);
153 MmCreatePeb(PEPROCESS Process
)
156 LARGE_INTEGER SectionOffset
;
158 PVOID TableBase
= NULL
;
159 PIMAGE_NT_HEADERS NtHeaders
;
160 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
162 KAFFINITY ProcessAffinityMask
= 0;
163 SectionOffset
.QuadPart
= (ULONGLONG
)0;
164 DPRINT("MmCreatePeb\n");
166 /* Allocate the PEB */
167 Peb
= MiCreatePebOrTeb(Process
,
168 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
169 ASSERT(Peb
== (PVOID
)0x7FFDF000);
172 DPRINT("Mapping NLS\n");
173 Status
= MmMapViewOfSection(ExpNlsSectionPointer
,
183 if (!NT_SUCCESS(Status
))
185 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
188 DPRINT("TableBase %p ViewSize %lx\n", TableBase
, ViewSize
);
190 /* Attach to Process */
191 KeAttachProcess(&Process
->Pcb
);
193 /* Initialize the PEB */
194 DPRINT("Allocated: %x\n", Peb
);
195 RtlZeroMemory(Peb
, sizeof(PEB
));
198 DPRINT("Setting up PEB\n");
199 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
200 Peb
->InheritedAddressSpace
= 0;
204 Peb
->AnsiCodePageData
= (PCHAR
)TableBase
+ ExpAnsiCodePageDataOffset
;
205 Peb
->OemCodePageData
= (PCHAR
)TableBase
+ ExpOemCodePageDataOffset
;
206 Peb
->UnicodeCaseTableData
= (PCHAR
)TableBase
+ ExpUnicodeCaseTableDataOffset
;
208 /* Default Version Data (could get changed below) */
209 Peb
->OSMajorVersion
= NtMajorVersion
;
210 Peb
->OSMinorVersion
= NtMinorVersion
;
211 Peb
->OSBuildNumber
= (USHORT
)(NtBuildNumber
& 0x3FFF);
212 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
213 Peb
->OSCSDVersion
= (USHORT
)CmNtCSDVersion
;
215 /* Heap and Debug Data */
216 Peb
->NumberOfProcessors
= KeNumberProcessors
;
217 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
218 Peb
->NtGlobalFlag
= NtGlobalFlag
;
219 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
220 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
221 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
222 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
223 Peb
->NumberOfHeaps
= 0;
224 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
225 Peb
->ProcessHeaps
= (PVOID
*)(Peb
+ 1);
228 if ((NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
)))
230 /* Write subsystem data */
231 Peb
->ImageSubSystem
= NtHeaders
->OptionalHeader
.Subsystem
;
232 Peb
->ImageSubSystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
233 Peb
->ImageSubSystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
235 /* Write Version Data */
236 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
238 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
239 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
240 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
242 /* Set the Platform ID */
243 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
246 /* Check if the image is not safe for SMP */
247 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
249 /* FIXME: Choose one randomly */
250 Peb
->ImageProcessAffinityMask
= 1;
254 /* Use affinity from Image Header */
255 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
260 /* Get the Image Config Data too */
261 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
263 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
266 ProbeForRead(ImageConfigData
,
267 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY
),
270 /* Process the image config data overrides if specfied. */
271 if (ImageConfigData
!= NULL
)
273 if (ImageConfigData
->CSDVersion
)
275 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
277 if (ImageConfigData
->ProcessAffinityMask
)
279 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
285 Status
= _SEH2_GetExceptionCode();
291 Peb
->SessionId
= Process
->Session
;
294 /* Detach from the Process */
297 DPRINT("MmCreatePeb: Peb created at %p\n", Peb
);
303 MmCreateTeb(PEPROCESS Process
,
305 PINITIAL_TEB InitialTeb
)
308 BOOLEAN Attached
= FALSE
;
310 /* Attach to the process */
311 DPRINT("MmCreateTeb\n");
312 if (Process
!= PsGetCurrentProcess())
314 /* Attach to Target */
315 KeAttachProcess(&Process
->Pcb
);
319 /* Allocate the TEB */
320 Teb
= MiCreatePebOrTeb(Process
,
321 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
323 /* Initialize the PEB */
324 RtlZeroMemory(Teb
, sizeof(TEB
));
327 Teb
->Tib
.ExceptionList
= (PVOID
)0xFFFFFFFF;
328 Teb
->Tib
.Version
= 1;
329 Teb
->Tib
.Self
= (PNT_TIB
)Teb
;
332 Teb
->ClientId
= *ClientId
;
333 Teb
->RealClientId
= *ClientId
;
334 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
335 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
337 /* Store stack information from InitialTeb */
338 if(InitialTeb
!= NULL
)
340 Teb
->Tib
.StackBase
= InitialTeb
->StackBase
;
341 Teb
->Tib
.StackLimit
= InitialTeb
->StackLimit
;
342 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
345 /* Initialize the static unicode string */
346 Teb
->StaticUnicodeString
.Length
= 0;
347 Teb
->StaticUnicodeString
.MaximumLength
= sizeof(Teb
->StaticUnicodeBuffer
);
348 Teb
->StaticUnicodeString
.Buffer
= Teb
->StaticUnicodeBuffer
;
350 /* Return TEB Address */
351 DPRINT("Allocated: %x\n", Teb
);
352 if (Attached
) KeDetachProcess();
358 MmInitializeHandBuiltProcess2(IN PEPROCESS Process
)
361 PMEMORY_AREA MemoryArea
;
362 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
364 PMMSUPPORT ProcessAddressSpace
= &Process
->Vm
;
365 BoundaryAddressMultiple
.QuadPart
= 0;
367 /* Create the shared data page */
368 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
369 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
370 MEMORY_AREA_SHARED_DATA
,
377 BoundaryAddressMultiple
);
383 MmInitializeProcessAddressSpace(IN PEPROCESS Process
,
384 IN PEPROCESS ProcessClone OPTIONAL
,
385 IN PVOID Section OPTIONAL
,
387 IN POBJECT_NAME_INFORMATION
*AuditName OPTIONAL
)
390 PMMSUPPORT ProcessAddressSpace
= &Process
->Vm
;
392 PMEMORY_AREA MemoryArea
;
393 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
396 PROS_SECTION_OBJECT SectionObject
= Section
;
397 BoundaryAddressMultiple
.QuadPart
= 0;
399 /* Initialize the Addresss Space lock */
400 KeInitializeGuardedMutex(&Process
->AddressCreationLock
);
401 Process
->Vm
.WorkingSetExpansionLinks
.Flink
= NULL
;
403 /* Initialize AVL tree */
404 ASSERT(Process
->VadRoot
.NumberGenericTableElements
== 0);
405 Process
->VadRoot
.BalancedRoot
.u1
.Parent
= &Process
->VadRoot
.BalancedRoot
;
407 /* Acquire the Lock */
408 MmLockAddressSpace(ProcessAddressSpace
);
410 /* Protect the highest 64KB of the process address space */
411 BaseAddress
= (PVOID
)MmUserProbeAddress
;
412 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
413 MEMORY_AREA_NO_ACCESS
,
420 BoundaryAddressMultiple
);
421 if (!NT_SUCCESS(Status
))
423 DPRINT1("Failed to protect last 64KB\n");
427 /* Protect the 60KB above the shared user page */
428 BaseAddress
= (char*)USER_SHARED_DATA
+ PAGE_SIZE
;
429 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
430 MEMORY_AREA_NO_ACCESS
,
437 BoundaryAddressMultiple
);
438 if (!NT_SUCCESS(Status
))
440 DPRINT1("Failed to protect the memory above the shared user page\n");
444 /* Create the shared data page */
445 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
446 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
447 MEMORY_AREA_SHARED_DATA
,
454 BoundaryAddressMultiple
);
455 if (!NT_SUCCESS(Status
))
457 DPRINT1("Failed to create Shared User Data\n");
461 /* The process now has an address space */
462 Process
->HasAddressSpace
= TRUE
;
464 /* Check if there's a Section Object */
467 UNICODE_STRING FileName
;
472 /* Unlock the Address Space */
473 DPRINT("Unlocking\n");
474 MmUnlockAddressSpace(ProcessAddressSpace
);
476 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
477 SectionObject
, Process
, &ImageBase
);
478 Status
= MmMapViewOfSection(Section
,
488 if (!NT_SUCCESS(Status
))
490 DPRINT1("Failed to map process Image\n");
494 /* Save the pointer */
495 Process
->SectionBaseAddress
= ImageBase
;
497 /* Determine the image file name and save it to EPROCESS */
498 DPRINT("Getting Image name\n");
499 FileName
= SectionObject
->FileObject
->FileName
;
500 szSrc
= (PWCHAR
)((PCHAR
)FileName
.Buffer
+ FileName
.Length
);
503 /* Loop the file name*/
504 while (szSrc
> FileName
.Buffer
)
506 /* Make sure this isn't a backslash */
507 if (*--szSrc
== OBJ_NAME_PATH_SEPARATOR
)
509 /* If so, stop it here */
515 /* Otherwise, keep going */
521 /* Copy the to the process and truncate it to 15 characters if necessary */
522 szDest
= Process
->ImageFileName
;
523 lnFName
= min(lnFName
, sizeof(Process
->ImageFileName
) - 1);
524 while (lnFName
--) *szDest
++ = (UCHAR
)*szSrc
++;
527 /* Check if caller wants an audit name */
530 /* Setup the audit name */
531 SeInitializeProcessAuditName(SectionObject
->FileObject
,
536 /* Return status to caller */
541 /* Unlock the Address Space */
542 DPRINT("Unlocking\n");
543 MmUnlockAddressSpace(ProcessAddressSpace
);
545 /* Return status to caller */
551 MmCleanProcessAddressSpace(IN PEPROCESS Process
)
553 /* FIXME: Add part of MmDeleteProcessAddressSpace here */
558 MmDeleteProcessAddressSpace(PEPROCESS Process
)
561 PMEMORY_AREA MemoryArea
;
563 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process
,
564 Process
->ImageFileName
);
566 MmLockAddressSpace(&Process
->Vm
);
568 while ((MemoryArea
= (PMEMORY_AREA
)Process
->Vm
.WorkingSetExpansionLinks
.Flink
) != NULL
)
570 switch (MemoryArea
->Type
)
572 case MEMORY_AREA_SECTION_VIEW
:
573 Address
= (PVOID
)MemoryArea
->StartingAddress
;
574 MmUnlockAddressSpace(&Process
->Vm
);
575 MmUnmapViewOfSection(Process
, Address
);
576 MmLockAddressSpace(&Process
->Vm
);
579 case MEMORY_AREA_VIRTUAL_MEMORY
:
580 case MEMORY_AREA_PEB_OR_TEB
:
581 MmFreeVirtualMemory(Process
, MemoryArea
);
584 case MEMORY_AREA_SHARED_DATA
:
585 case MEMORY_AREA_NO_ACCESS
:
586 MmFreeMemoryArea(&Process
->Vm
,
592 case MEMORY_AREA_MDL_MAPPING
:
593 KeBugCheck(PROCESS_HAS_LOCKED_PAGES
);
597 KeBugCheck(MEMORY_MANAGEMENT
);
601 Mmi386ReleaseMmInfo(Process
);
603 MmUnlockAddressSpace(&Process
->Vm
);
605 DPRINT("Finished MmReleaseMmInfo()\n");
606 return(STATUS_SUCCESS
);