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 NtOSCSDVersion
;
19 extern ULONG NtGlobalFlag
;
21 #define MM_HIGHEST_VAD_ADDRESS \
22 (PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
24 /* FUNCTIONS *****************************************************************/
28 MiCreatePebOrTeb(PROS_EPROCESS Process
,
32 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
33 PMEMORY_AREA MemoryArea
;
34 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
35 PVOID AllocatedBase
= BaseAddress
;
36 BoundaryAddressMultiple
.QuadPart
= 0;
38 /* Acquire the Lock */
39 MmLockAddressSpace(ProcessAddressSpace
);
42 * Create a Peb or Teb.
43 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
44 * is that a PEB allocation should never fail since the address is free,
45 * while TEB allocation can fail, and we should simply try the address
46 * below. Is there a nicer way of doing this automagically? (ie: findning)
47 * a gap region? -- Alex
50 DPRINT("Trying to allocate: %x\n", AllocatedBase
);
51 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
52 MEMORY_AREA_PEB_OR_TEB
,
59 BoundaryAddressMultiple
);
60 AllocatedBase
= RVA(AllocatedBase
, -PAGE_SIZE
);
61 } while (Status
!= STATUS_SUCCESS
);
63 /* Initialize the Region */
64 MmInitializeRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
69 /* Reserve the pages */
70 MmReserveSwapPages(PAGE_SIZE
);
72 /* Unlock Address Space */
73 DPRINT("Returning\n");
74 MmUnlockAddressSpace(ProcessAddressSpace
);
75 return RVA(AllocatedBase
, PAGE_SIZE
);
79 MiFreeStackPage(PVOID Context
,
80 MEMORY_AREA
* MemoryArea
,
86 ASSERT(SwapEntry
== 0);
87 if (Page
) MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
92 MmDeleteKernelStack(PVOID Stack
,
95 /* Lock the Address Space */
96 MmLockAddressSpace(MmGetKernelAddressSpace());
98 /* Delete the Stack */
99 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
104 /* Unlock the Address Space */
105 MmUnlockAddressSpace(MmGetKernelAddressSpace());
110 MmDeleteTeb(PROS_EPROCESS Process
,
113 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
114 PMEMORY_AREA MemoryArea
;
116 /* Lock the Address Space */
117 MmLockAddressSpace(ProcessAddressSpace
);
119 MemoryArea
= MmLocateMemoryAreaByAddress(ProcessAddressSpace
, (PVOID
)Teb
);
123 MmFreeVirtualMemory(Process
, MemoryArea
);
126 /* Unlock the Address Space */
127 MmUnlockAddressSpace(ProcessAddressSpace
);
132 MmCreateKernelStack(BOOLEAN GuiStack
)
134 PMEMORY_AREA StackArea
;
136 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
137 ULONG StackSize
= GuiStack
? KERNEL_LARGE_STACK_SIZE
: KERNEL_STACK_SIZE
;
138 PFN_TYPE Page
[KERNEL_LARGE_STACK_SIZE
/ PAGE_SIZE
];
139 PVOID KernelStack
= NULL
;
142 /* Initialize the Boundary Address */
143 BoundaryAddressMultiple
.QuadPart
= 0;
145 /* Lock the Kernel Address Space */
146 MmLockAddressSpace(MmGetKernelAddressSpace());
148 /* Create a MAREA for the Kernel Stack */
149 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
150 MEMORY_AREA_KERNEL_STACK
,
157 BoundaryAddressMultiple
);
159 /* Unlock the Address Space */
160 MmUnlockAddressSpace(MmGetKernelAddressSpace());
162 /* Check for Success */
163 if (!NT_SUCCESS(Status
))
165 DPRINT1("Failed to create thread stack\n");
170 * Mark the Stack in use.
171 * Note: Currently we mark all 60KB in use for a GUI Thread.
172 * We should only do this inside MmGrowKernelStack. TODO!
174 for (i
= 0; i
< (StackSize
/ PAGE_SIZE
); i
++)
176 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
179 /* Create a Virtual Mapping for it */
180 Status
= MmCreateVirtualMapping(NULL
,
184 StackSize
/ PAGE_SIZE
);
186 /* Check for success */
187 if (!NT_SUCCESS(Status
))
189 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
193 /* Return the stack */
202 MmGrowKernelStack(PVOID StackPointer
)
204 PETHREAD Thread
= PsGetCurrentThread();
206 /* Make sure we have reserved space for our grow */
207 ASSERT(((PCHAR
)Thread
->Tcb
.StackBase
- (PCHAR
)Thread
->Tcb
.StackLimit
) <=
208 (KERNEL_LARGE_STACK_SIZE
+ PAGE_SIZE
));
211 * We'll give you three more pages.
212 * NOTE: See note in MmCreateKernelStack. These pages are already being reserved.
213 * It would be more efficient to only grow them (commit them) here.
215 Thread
->Tcb
.StackLimit
-= KERNEL_STACK_SIZE
;
218 return STATUS_SUCCESS
;
223 MmCreatePeb(PROS_EPROCESS Process
)
226 LARGE_INTEGER SectionOffset
;
228 PVOID TableBase
= NULL
;
229 PIMAGE_NT_HEADERS NtHeaders
;
230 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
232 KAFFINITY ProcessAffinityMask
= 0;
233 SectionOffset
.QuadPart
= (ULONGLONG
)0;
234 DPRINT("MmCreatePeb\n");
236 /* Allocate the PEB */
237 Peb
= MiCreatePebOrTeb(Process
,
238 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
239 ASSERT(Peb
== (PVOID
)0x7FFDF000);
242 DPRINT("Mapping NLS\n");
243 Status
= MmMapViewOfSection(NlsSectionObject
,
253 if (!NT_SUCCESS(Status
))
255 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
258 DPRINT("TableBase %p ViewSize %lx\n", TableBase
, ViewSize
);
260 /* Attach to Process */
261 KeAttachProcess(&Process
->Pcb
);
263 /* Initialize the PEB */
264 DPRINT("Allocated: %x\n", Peb
);
265 RtlZeroMemory(Peb
, sizeof(PEB
));
268 DPRINT("Setting up PEB\n");
269 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
270 Peb
->InheritedAddressSpace
= 0;
274 Peb
->AnsiCodePageData
= (char*)TableBase
+ NlsAnsiTableOffset
;
275 Peb
->OemCodePageData
= (char*)TableBase
+ NlsOemTableOffset
;
276 Peb
->UnicodeCaseTableData
= (char*)TableBase
+ NlsUnicodeTableOffset
;
278 /* Default Version Data (could get changed below) */
279 Peb
->OSMajorVersion
= NtMajorVersion
;
280 Peb
->OSMinorVersion
= NtMinorVersion
;
281 Peb
->OSBuildNumber
= 2195;
282 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
283 Peb
->OSCSDVersion
= NtOSCSDVersion
;
285 /* Heap and Debug Data */
286 Peb
->NumberOfProcessors
= KeNumberProcessors
;
287 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
288 Peb
->NtGlobalFlag
= NtGlobalFlag
;
289 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
290 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
291 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
292 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
293 Peb
->NumberOfHeaps
= 0;
294 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
295 Peb
->ProcessHeaps
= (PVOID
*)Peb
+ 1;
298 if ((NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
)))
300 /* Get the Image Config Data too */
301 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
303 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
306 /* Write subsystem data */
307 Peb
->ImageSubSystem
= NtHeaders
->OptionalHeader
.Subsystem
;
308 Peb
->ImageSubSystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
309 Peb
->ImageSubSystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
311 /* Write Version Data */
312 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
314 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
315 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
316 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
318 /* Lie about the version if requested */
319 if (ImageConfigData
&& ImageConfigData
->CSDVersion
)
321 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
324 /* Set the Platform ID */
325 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
328 /* Check for affinity override */
329 if (ImageConfigData
&& ImageConfigData
->ProcessAffinityMask
)
331 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
334 /* Check if the image is not safe for SMP */
335 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
337 /* FIXME: Choose one randomly */
338 Peb
->ImageProcessAffinityMask
= 1;
342 /* Use affinity from Image Header */
343 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
348 Peb
->SessionId
= Process
->Session
;
351 /* Detach from the Process */
354 DPRINT("MmCreatePeb: Peb created at %p\n", Peb
);
355 return STATUS_SUCCESS
;
360 MmCreateTeb(PROS_EPROCESS Process
,
362 PINITIAL_TEB InitialTeb
)
365 BOOLEAN Attached
= FALSE
;
367 /* Attach to the process */
368 DPRINT("MmCreateTeb\n");
369 if (Process
!= (PROS_EPROCESS
)PsGetCurrentProcess())
371 /* Attach to Target */
372 KeAttachProcess(&Process
->Pcb
);
376 /* Allocate the TEB */
377 Teb
= MiCreatePebOrTeb(Process
,
378 (PVOID
)((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
380 /* Initialize the PEB */
381 RtlZeroMemory(Teb
, sizeof(TEB
));
384 Teb
->Tib
.ExceptionList
= (PVOID
)0xFFFFFFFF;
385 Teb
->Tib
.Version
= 1;
386 Teb
->Tib
.Self
= (PNT_TIB
)Teb
;
389 Teb
->Cid
= *ClientId
;
390 Teb
->RealClientId
= *ClientId
;
391 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
392 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
394 /* Store stack information from InitialTeb */
395 if(InitialTeb
!= NULL
)
397 Teb
->Tib
.StackBase
= InitialTeb
->StackBase
;
398 Teb
->Tib
.StackLimit
= InitialTeb
->StackLimit
;
399 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
402 /* Return TEB Address */
403 DPRINT("Allocated: %x\n", Teb
);
404 if (Attached
) KeDetachProcess();
410 MmCreateProcessAddressSpace(IN PROS_EPROCESS Process
,
411 IN PROS_SECTION_OBJECT Section OPTIONAL
)
414 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
416 PMEMORY_AREA MemoryArea
;
417 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
420 BoundaryAddressMultiple
.QuadPart
= 0;
422 /* Initialize the Addresss Space */
423 MmInitializeAddressSpace(Process
, ProcessAddressSpace
);
425 /* Acquire the Lock */
426 MmLockAddressSpace(ProcessAddressSpace
);
428 /* Protect the highest 64KB of the process address space */
429 BaseAddress
= (PVOID
)MmUserProbeAddress
;
430 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
431 MEMORY_AREA_NO_ACCESS
,
438 BoundaryAddressMultiple
);
439 if (!NT_SUCCESS(Status
))
441 DPRINT1("Failed to protect last 64KB\n");
445 /* Protect the 60KB above the shared user page */
446 BaseAddress
= (char*)USER_SHARED_DATA
+ PAGE_SIZE
;
447 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
448 MEMORY_AREA_NO_ACCESS
,
455 BoundaryAddressMultiple
);
456 if (!NT_SUCCESS(Status
))
458 DPRINT1("Failed to protect the memory above the shared user page\n");
462 /* Create the shared data page */
463 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
464 Status
= MmCreateMemoryArea(ProcessAddressSpace
,
465 MEMORY_AREA_SHARED_DATA
,
472 BoundaryAddressMultiple
);
473 if (!NT_SUCCESS(Status
))
475 DPRINT1("Failed to create Shared User Data\n");
479 /* Check if there's a Section Object */
482 UNICODE_STRING FileName
;
487 /* Unlock the Address Space */
488 DPRINT("Unlocking\n");
489 MmUnlockAddressSpace(ProcessAddressSpace
);
491 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
492 Section
, Process
, &ImageBase
);
493 Status
= MmMapViewOfSection(Section
,
503 if (!NT_SUCCESS(Status
))
505 DPRINT1("Failed to map process Image\n");
509 /* Save the pointer */
510 Process
->SectionBaseAddress
= ImageBase
;
512 /* Determine the image file name and save it to EPROCESS */
513 DPRINT("Getting Image name\n");
514 FileName
= Section
->FileObject
->FileName
;
515 szSrc
= (PWCHAR
)(FileName
.Buffer
+ (FileName
.Length
/ sizeof(WCHAR
)) - 1);
517 while(szSrc
>= FileName
.Buffer
)
531 /* Copy the to the process and truncate it to 15 characters if necessary */
532 DPRINT("Copying and truncating\n");
533 szDest
= Process
->ImageFileName
;
534 lnFName
= min(lnFName
, sizeof(Process
->ImageFileName
) - 1);
535 while(lnFName
-- > 0) *(szDest
++) = (UCHAR
)*(szSrc
++);
537 /* Return status to caller */
542 /* Unlock the Address Space */
543 DPRINT("Unlocking\n");
544 MmUnlockAddressSpace(ProcessAddressSpace
);
546 /* Return status to caller */