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 /* FUNCTIONS *****************************************************************/
25 MiCreatePebOrTeb(PEPROCESS Process
,
29 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
30 PMEMORY_AREA MemoryArea
;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
32 PVOID AllocatedBase
= BaseAddress
;
33 BoundaryAddressMultiple
.QuadPart
= 0;
35 /* Acquire the Lock */
36 MmLockAddressSpace(ProcessAddressSpace
);
39 * Create a Peb or Teb.
40 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
41 * is that a PEB allocation should never fail since the address is free,
42 * while TEB allocation can fail, and we should simply try the address
43 * below. Is there a nicer way of doing this automagically? (ie: findning)
44 * a gap region? -- Alex
47 DPRINT("Trying to allocate: %x\n", AllocatedBase
);
48 Status
= MmCreateMemoryArea(Process
,
50 MEMORY_AREA_PEB_OR_TEB
,
57 BoundaryAddressMultiple
);
58 AllocatedBase
= RVA(AllocatedBase
, -PAGE_SIZE
);
59 } while (Status
!= STATUS_SUCCESS
);
61 /* Initialize the Region */
62 MmInitialiseRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
67 /* Reserve the pages */
68 MmReserveSwapPages(PAGE_SIZE
);
70 /* Unlock Address Space */
71 DPRINT("Returning\n");
72 MmUnlockAddressSpace(ProcessAddressSpace
);
73 return RVA(AllocatedBase
, PAGE_SIZE
);
77 MiFreeStackPage(PVOID Context
,
78 MEMORY_AREA
* MemoryArea
,
84 ASSERT(SwapEntry
== 0);
85 if (Page
) MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
90 MmDeleteKernelStack(PVOID Stack
,
93 /* Lock the Address Space */
94 MmLockAddressSpace(MmGetKernelAddressSpace());
96 /* Delete the Stack */
97 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
102 /* Unlock the Address Space */
103 MmUnlockAddressSpace(MmGetKernelAddressSpace());
107 MiFreePebPage(PVOID Context
,
108 MEMORY_AREA
* MemoryArea
,
114 PEPROCESS Process
= (PEPROCESS
)Context
;
118 SWAPENTRY SavedSwapEntry
;
119 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
120 if (SavedSwapEntry
!= 0)
122 MmFreeSwapPage(SavedSwapEntry
);
123 MmSetSavedSwapEntryPage(Page
, 0);
125 MmDeleteRmap(Page
, Process
, Address
);
126 MmReleasePageMemoryConsumer(MC_USER
, Page
);
128 else if (SwapEntry
!= 0)
130 MmFreeSwapPage(SwapEntry
);
136 MmDeleteTeb(PEPROCESS Process
,
139 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
141 /* Lock the Address Space */
142 MmLockAddressSpace(ProcessAddressSpace
);
144 /* Delete the Stack */
145 MmFreeMemoryAreaByPtr(ProcessAddressSpace
,
150 /* Unlock the Address Space */
151 MmUnlockAddressSpace(ProcessAddressSpace
);
156 MmCreateKernelStack(BOOLEAN GuiStack
)
158 PMEMORY_AREA StackArea
;
160 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
161 PFN_TYPE Page
[MM_STACK_SIZE
/ PAGE_SIZE
];
162 PVOID KernelStack
= NULL
;
165 /* Initialize the Boundary Address */
166 BoundaryAddressMultiple
.QuadPart
= 0;
168 /* Lock the Kernel Address Space */
169 MmLockAddressSpace(MmGetKernelAddressSpace());
171 /* Create a MAREA for the Kernel Stack */
172 Status
= MmCreateMemoryArea(NULL
,
173 MmGetKernelAddressSpace(),
174 MEMORY_AREA_KERNEL_STACK
,
181 BoundaryAddressMultiple
);
183 /* Unlock the Address Space */
184 MmUnlockAddressSpace(MmGetKernelAddressSpace());
186 /* Check for Success */
187 if (!NT_SUCCESS(Status
))
189 DPRINT1("Failed to create thread stack\n");
193 /* Mark the Stack in use */
194 for (i
= 0; i
< (MM_STACK_SIZE
/ PAGE_SIZE
); i
++)
196 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
[i
]);
199 /* Create a Virtual Mapping for it */
200 Status
= MmCreateVirtualMapping(NULL
,
204 MM_STACK_SIZE
/ PAGE_SIZE
);
206 /* Check for success */
207 if (!NT_SUCCESS(Status
))
209 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
218 MmCreatePeb(PEPROCESS Process
)
221 LARGE_INTEGER SectionOffset
;
223 PVOID TableBase
= NULL
;
224 PIMAGE_NT_HEADERS NtHeaders
;
225 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData
;
227 KAFFINITY ProcessAffinityMask
= 0;
228 SectionOffset
.QuadPart
= (ULONGLONG
)0;
230 DPRINT("MmCreatePeb\n");
233 DPRINT("Mapping NLS\n");
234 Status
= MmMapViewOfSection(NlsSectionObject
,
244 if (!NT_SUCCESS(Status
))
246 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status
);
249 DPRINT("TableBase %p ViewSize %lx\n", TableBase
, ViewSize
);
251 /* Attach to Process */
252 KeAttachProcess(&Process
->Pcb
);
254 /* Allocate the PEB */
255 Peb
= MiCreatePebOrTeb(Process
, (PVOID
)PEB_BASE
);
257 /* Initialize the PEB */
258 DPRINT("Allocated: %x\n", Peb
);
259 RtlZeroMemory(Peb
, sizeof(PEB
));
262 DPRINT("Setting up PEB\n");
263 Peb
->ImageBaseAddress
= Process
->SectionBaseAddress
;
264 Peb
->InheritedAddressSpace
= 0;
268 Peb
->AnsiCodePageData
= (char*)TableBase
+ NlsAnsiTableOffset
;
269 Peb
->OemCodePageData
= (char*)TableBase
+ NlsOemTableOffset
;
270 Peb
->UnicodeCaseTableData
= (char*)TableBase
+ NlsUnicodeTableOffset
;
272 /* Default Version Data (could get changed below) */
273 Peb
->OSMajorVersion
= NtMajorVersion
;
274 Peb
->OSMinorVersion
= NtMinorVersion
;
275 Peb
->OSBuildNumber
= 2195;
276 Peb
->OSPlatformId
= 2; /* VER_PLATFORM_WIN32_NT */
277 Peb
->OSCSDVersion
= NtOSCSDVersion
;
279 /* Heap and Debug Data */
280 Peb
->NumberOfProcessors
= KeNumberProcessors
;
281 Peb
->BeingDebugged
= (BOOLEAN
)(Process
->DebugPort
!= NULL
? TRUE
: FALSE
);
282 Peb
->NtGlobalFlag
= NtGlobalFlag
;
283 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
284 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
285 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
286 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
287 Peb
->NumberOfHeaps
= 0;
288 Peb
->MaximumNumberOfHeaps
= (PAGE_SIZE
- sizeof(PEB
)) / sizeof(PVOID
);
289 Peb
->ProcessHeaps
= (PVOID
*)Peb
+ 1;
292 if ((NtHeaders
= RtlImageNtHeader(Peb
->ImageBaseAddress
)))
294 /* Get the Image Config Data too */
295 ImageConfigData
= RtlImageDirectoryEntryToData(Peb
->ImageBaseAddress
,
297 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
,
300 /* Write subsystem data */
301 Peb
->ImageSubSystem
= NtHeaders
->OptionalHeader
.Subsystem
;
302 Peb
->ImageSubSystemMajorVersion
= NtHeaders
->OptionalHeader
.MajorSubsystemVersion
;
303 Peb
->ImageSubSystemMinorVersion
= NtHeaders
->OptionalHeader
.MinorSubsystemVersion
;
305 /* Write Version Data */
306 if (NtHeaders
->OptionalHeader
.Win32VersionValue
)
308 Peb
->OSMajorVersion
= NtHeaders
->OptionalHeader
.Win32VersionValue
& 0xFF;
309 Peb
->OSMinorVersion
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 8) & 0xFF;
310 Peb
->OSBuildNumber
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 16) & 0x3FFF;
312 /* Lie about the version if requested */
313 if (ImageConfigData
&& ImageConfigData
->CSDVersion
)
315 Peb
->OSCSDVersion
= ImageConfigData
->CSDVersion
;
318 /* Set the Platform ID */
319 Peb
->OSPlatformId
= (NtHeaders
->OptionalHeader
.Win32VersionValue
>> 30) ^ 2;
322 /* Check for affinity override */
323 if (ImageConfigData
&& ImageConfigData
->ProcessAffinityMask
)
325 ProcessAffinityMask
= ImageConfigData
->ProcessAffinityMask
;
328 /* Check if the image is not safe for SMP */
329 if (NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
)
331 /* FIXME: Choose one randomly */
332 Peb
->ImageProcessAffinityMask
= 1;
336 /* Use affinity from Image Header */
337 Peb
->ImageProcessAffinityMask
= ProcessAffinityMask
;
342 Peb
->SessionId
= Process
->Session
;
345 /* Detach from the Process */
348 DPRINT("MmCreatePeb: Peb created at %p\n", Peb
);
349 return STATUS_SUCCESS
;
354 MmCreateTeb(PEPROCESS Process
,
356 PINITIAL_TEB InitialTeb
)
359 BOOLEAN Attached
= FALSE
;
361 /* Attach to the process */
362 DPRINT("MmCreateTeb\n");
363 if (Process
!= PsGetCurrentProcess())
365 /* Attach to Target */
366 KeAttachProcess(&Process
->Pcb
);
370 /* Allocate the TEB */
371 Teb
= MiCreatePebOrTeb(Process
, (PVOID
)TEB_BASE
);
373 /* Initialize the PEB */
374 RtlZeroMemory(Teb
, sizeof(TEB
));
377 Teb
->Tib
.ExceptionList
= (PVOID
)0xFFFFFFFF;
378 Teb
->Tib
.Version
= 1;
379 Teb
->Tib
.Self
= (PNT_TIB
)Teb
;
382 Teb
->Cid
= *ClientId
;
383 Teb
->RealClientId
= *ClientId
;
384 Teb
->ProcessEnvironmentBlock
= Process
->Peb
;
385 Teb
->CurrentLocale
= PsDefaultThreadLocaleId
;
387 /* Store stack information from InitialTeb */
388 if(InitialTeb
!= NULL
)
390 Teb
->Tib
.StackBase
= InitialTeb
->StackBase
;
391 Teb
->Tib
.StackLimit
= InitialTeb
->StackLimit
;
392 Teb
->DeallocationStack
= InitialTeb
->AllocatedStackBase
;
395 /* Return TEB Address */
396 DPRINT("Allocated: %x\n", Teb
);
397 if (Attached
) KeDetachProcess();
403 MmCreateProcessAddressSpace(IN PEPROCESS Process
,
404 IN PSECTION_OBJECT Section OPTIONAL
)
407 PMADDRESS_SPACE ProcessAddressSpace
= &Process
->AddressSpace
;
409 PMEMORY_AREA MemoryArea
;
410 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
413 BoundaryAddressMultiple
.QuadPart
= 0;
415 /* Initialize the Addresss Space */
416 MmInitializeAddressSpace(Process
, ProcessAddressSpace
);
418 /* Acquire the Lock */
419 MmLockAddressSpace(ProcessAddressSpace
);
421 /* Protect the highest 64KB of the process address space */
422 BaseAddress
= (PVOID
)MmUserProbeAddress
;
423 Status
= MmCreateMemoryArea(Process
,
425 MEMORY_AREA_NO_ACCESS
,
432 BoundaryAddressMultiple
);
433 if (!NT_SUCCESS(Status
))
435 DPRINT1("Failed to protect last 64KB\n");
439 /* Protect the 60KB above the shared user page */
440 BaseAddress
= (char*)USER_SHARED_DATA
+ PAGE_SIZE
;
441 Status
= MmCreateMemoryArea(Process
,
443 MEMORY_AREA_NO_ACCESS
,
450 BoundaryAddressMultiple
);
451 if (!NT_SUCCESS(Status
))
453 DPRINT1("Failed to protect the memory above the shared user page\n");
457 /* Create the shared data page */
458 BaseAddress
= (PVOID
)USER_SHARED_DATA
;
459 Status
= MmCreateMemoryArea(Process
,
461 MEMORY_AREA_SHARED_DATA
,
468 BoundaryAddressMultiple
);
469 if (!NT_SUCCESS(Status
))
471 DPRINT1("Failed to create Shared User Data\n");
475 /* Check if there's a Section Object */
478 UNICODE_STRING FileName
;
483 /* Unlock the Address Space */
484 DPRINT("Unlocking\n");
485 MmUnlockAddressSpace(ProcessAddressSpace
);
487 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
488 Section
, Process
, &ImageBase
);
489 Status
= MmMapViewOfSection(Section
,
499 if (!NT_SUCCESS(Status
))
501 DPRINT1("Failed to map process Image\n");
502 ObDereferenceObject(Section
);
505 ObDereferenceObject(Section
);
507 /* Save the pointer */
508 Process
->SectionBaseAddress
= ImageBase
;
510 /* Determine the image file name and save it to EPROCESS */
511 DPRINT("Getting Image name\n");
512 FileName
= Section
->FileObject
->FileName
;
513 szSrc
= (PWCHAR
)(FileName
.Buffer
+ (FileName
.Length
/ sizeof(WCHAR
)) - 1);
515 while(szSrc
>= FileName
.Buffer
)
529 /* Copy the to the process and truncate it to 15 characters if necessary */
530 DPRINT("Copying and truncating\n");
531 szDest
= Process
->ImageFileName
;
532 lnFName
= min(lnFName
, sizeof(Process
->ImageFileName
) - 1);
533 while(lnFName
-- > 0) *(szDest
++) = (UCHAR
)*(szSrc
++);
535 /* Return status to caller */
540 /* Unlock the Address Space */
541 DPRINT("Unlocking\n");
542 MmUnlockAddressSpace(ProcessAddressSpace
);
544 /* Return status to caller */