3577dd27dd166fc86f53bf42a9131521cc1f7028
[reactos.git] / reactos / ntoskrnl / mm / process.c
1 /*
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
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 extern ULONG NtMajorVersion;
17 extern ULONG NtMinorVersion;
18 extern ULONG NtOSCSDVersion;
19 extern ULONG NtGlobalFlag;
20
21 /* FUNCTIONS *****************************************************************/
22
23 PVOID
24 STDCALL
25 MiCreatePebOrTeb(PEPROCESS Process,
26 PVOID BaseAddress)
27 {
28 NTSTATUS Status;
29 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
30 PMEMORY_AREA MemoryArea;
31 PHYSICAL_ADDRESS BoundaryAddressMultiple;
32 PVOID AllocatedBase = BaseAddress;
33 BoundaryAddressMultiple.QuadPart = 0;
34
35 /* Acquire the Lock */
36 MmLockAddressSpace(ProcessAddressSpace);
37
38 /*
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
45 */
46 do {
47 DPRINT("Trying to allocate: %x\n", AllocatedBase);
48 Status = MmCreateMemoryArea(Process,
49 ProcessAddressSpace,
50 MEMORY_AREA_PEB_OR_TEB,
51 &AllocatedBase,
52 PAGE_SIZE,
53 PAGE_READWRITE,
54 &MemoryArea,
55 TRUE,
56 FALSE,
57 BoundaryAddressMultiple);
58 AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
59 } while (Status != STATUS_SUCCESS);
60
61 /* Initialize the Region */
62 MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
63 PAGE_SIZE,
64 MEM_COMMIT,
65 PAGE_READWRITE);
66
67 /* Reserve the pages */
68 MmReserveSwapPages(PAGE_SIZE);
69
70 /* Unlock Address Space */
71 DPRINT("Returning\n");
72 MmUnlockAddressSpace(ProcessAddressSpace);
73 return RVA(AllocatedBase, PAGE_SIZE);
74 }
75
76 VOID
77 MiFreeStackPage(PVOID Context,
78 MEMORY_AREA* MemoryArea,
79 PVOID Address,
80 PFN_TYPE Page,
81 SWAPENTRY SwapEntry,
82 BOOLEAN Dirty)
83 {
84 ASSERT(SwapEntry == 0);
85 if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
86 }
87
88 VOID
89 STDCALL
90 MmDeleteKernelStack(PVOID Stack,
91 BOOLEAN GuiStack)
92 {
93 /* Lock the Address Space */
94 MmLockAddressSpace(MmGetKernelAddressSpace());
95
96 /* Delete the Stack */
97 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
98 Stack,
99 MiFreeStackPage,
100 NULL);
101
102 /* Unlock the Address Space */
103 MmUnlockAddressSpace(MmGetKernelAddressSpace());
104 }
105
106 VOID
107 STDCALL
108 MmDeleteTeb(PEPROCESS Process,
109 PTEB Teb)
110 {
111 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
112 PMEMORY_AREA MemoryArea;
113
114 /* Lock the Address Space */
115 MmLockAddressSpace(ProcessAddressSpace);
116
117 MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
118 if (MemoryArea)
119 {
120 /* Delete the Teb */
121 MmFreeVirtualMemory(Process, MemoryArea);
122 }
123
124 /* Unlock the Address Space */
125 MmUnlockAddressSpace(ProcessAddressSpace);
126 }
127
128 PVOID
129 STDCALL
130 MmCreateKernelStack(BOOLEAN GuiStack)
131 {
132 PMEMORY_AREA StackArea;
133 ULONG i;
134 PHYSICAL_ADDRESS BoundaryAddressMultiple;
135 PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
136 PVOID KernelStack = NULL;
137 NTSTATUS Status;
138
139 /* Initialize the Boundary Address */
140 BoundaryAddressMultiple.QuadPart = 0;
141
142 /* Lock the Kernel Address Space */
143 MmLockAddressSpace(MmGetKernelAddressSpace());
144
145 /* Create a MAREA for the Kernel Stack */
146 Status = MmCreateMemoryArea(NULL,
147 MmGetKernelAddressSpace(),
148 MEMORY_AREA_KERNEL_STACK,
149 &KernelStack,
150 MM_STACK_SIZE,
151 0,
152 &StackArea,
153 FALSE,
154 FALSE,
155 BoundaryAddressMultiple);
156
157 /* Unlock the Address Space */
158 MmUnlockAddressSpace(MmGetKernelAddressSpace());
159
160 /* Check for Success */
161 if (!NT_SUCCESS(Status))
162 {
163 DPRINT1("Failed to create thread stack\n");
164 KEBUGCHECK(0);
165 }
166
167 /* Mark the Stack in use */
168 for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
169 {
170 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
171 }
172
173 /* Create a Virtual Mapping for it */
174 Status = MmCreateVirtualMapping(NULL,
175 KernelStack,
176 PAGE_READWRITE,
177 Page,
178 MM_STACK_SIZE / PAGE_SIZE);
179
180 /* Check for success */
181 if (!NT_SUCCESS(Status))
182 {
183 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
184 KEBUGCHECK(0);
185 }
186
187 return KernelStack;
188 }
189
190 NTSTATUS
191 STDCALL
192 MmCreatePeb(PEPROCESS Process)
193 {
194 PPEB Peb = NULL;
195 LARGE_INTEGER SectionOffset;
196 ULONG ViewSize = 0;
197 PVOID TableBase = NULL;
198 PIMAGE_NT_HEADERS NtHeaders;
199 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
200 NTSTATUS Status;
201 KAFFINITY ProcessAffinityMask = 0;
202 SectionOffset.QuadPart = (ULONGLONG)0;
203
204 DPRINT("MmCreatePeb\n");
205
206 /* Allocate the PEB */
207 Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE);
208 if (Peb != (PVOID)PEB_BASE)
209 {
210 DPRINT1("MiCreatePebOrTeb() returned %x\n", Peb);
211 return STATUS_UNSUCCESSFUL;
212 }
213
214 /* Map NLS Tables */
215 DPRINT("Mapping NLS\n");
216 Status = MmMapViewOfSection(NlsSectionObject,
217 Process,
218 &TableBase,
219 0,
220 0,
221 &SectionOffset,
222 &ViewSize,
223 ViewShare,
224 MEM_TOP_DOWN,
225 PAGE_READONLY);
226 if (!NT_SUCCESS(Status))
227 {
228 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
229 return(Status);
230 }
231 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
232
233 /* Attach to Process */
234 KeAttachProcess(&Process->Pcb);
235
236 /* Initialize the PEB */
237 DPRINT("Allocated: %x\n", Peb);
238 RtlZeroMemory(Peb, sizeof(PEB));
239
240 /* Set up data */
241 DPRINT("Setting up PEB\n");
242 Peb->ImageBaseAddress = Process->SectionBaseAddress;
243 Peb->InheritedAddressSpace = 0;
244 Peb->Mutant = NULL;
245
246 /* NLS */
247 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
248 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
249 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
250
251 /* Default Version Data (could get changed below) */
252 Peb->OSMajorVersion = NtMajorVersion;
253 Peb->OSMinorVersion = NtMinorVersion;
254 Peb->OSBuildNumber = 2195;
255 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
256 Peb->OSCSDVersion = NtOSCSDVersion;
257
258 /* Heap and Debug Data */
259 Peb->NumberOfProcessors = KeNumberProcessors;
260 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
261 Peb->NtGlobalFlag = NtGlobalFlag;
262 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
263 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
264 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
265 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
266 Peb->NumberOfHeaps = 0;
267 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
268 Peb->ProcessHeaps = (PVOID*)Peb + 1;
269
270 /* Image Data */
271 if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
272 {
273 /* Get the Image Config Data too */
274 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
275 TRUE,
276 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
277 &ViewSize);
278
279 /* Write subsystem data */
280 Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
281 Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
282 Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
283
284 /* Write Version Data */
285 if (NtHeaders->OptionalHeader.Win32VersionValue)
286 {
287 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
288 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
289 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
290
291 /* Lie about the version if requested */
292 if (ImageConfigData && ImageConfigData->CSDVersion)
293 {
294 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
295 }
296
297 /* Set the Platform ID */
298 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
299 }
300
301 /* Check for affinity override */
302 if (ImageConfigData && ImageConfigData->ProcessAffinityMask)
303 {
304 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
305 }
306
307 /* Check if the image is not safe for SMP */
308 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
309 {
310 /* FIXME: Choose one randomly */
311 Peb->ImageProcessAffinityMask = 1;
312 }
313 else
314 {
315 /* Use affinity from Image Header */
316 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
317 }
318 }
319
320 /* Misc data */
321 Peb->SessionId = Process->Session;
322 Process->Peb = Peb;
323
324 /* Detach from the Process */
325 KeDetachProcess();
326
327 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
328 return STATUS_SUCCESS;
329 }
330
331 PTEB
332 STDCALL
333 MmCreateTeb(PEPROCESS Process,
334 PCLIENT_ID ClientId,
335 PINITIAL_TEB InitialTeb)
336 {
337 PTEB Teb;
338 BOOLEAN Attached = FALSE;
339
340 /* Attach to the process */
341 DPRINT("MmCreateTeb\n");
342 if (Process != PsGetCurrentProcess())
343 {
344 /* Attach to Target */
345 KeAttachProcess(&Process->Pcb);
346 Attached = TRUE;
347 }
348
349 /* Allocate the TEB */
350 Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE);
351
352 /* Initialize the PEB */
353 RtlZeroMemory(Teb, sizeof(TEB));
354
355 /* Set TIB Data */
356 Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
357 Teb->Tib.Version = 1;
358 Teb->Tib.Self = (PNT_TIB)Teb;
359
360 /* Set TEB Data */
361 Teb->Cid = *ClientId;
362 Teb->RealClientId = *ClientId;
363 Teb->ProcessEnvironmentBlock = Process->Peb;
364 Teb->CurrentLocale = PsDefaultThreadLocaleId;
365
366 /* Store stack information from InitialTeb */
367 if(InitialTeb != NULL)
368 {
369 Teb->Tib.StackBase = InitialTeb->StackBase;
370 Teb->Tib.StackLimit = InitialTeb->StackLimit;
371 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
372 }
373
374 /* Return TEB Address */
375 DPRINT("Allocated: %x\n", Teb);
376 if (Attached) KeDetachProcess();
377 return Teb;
378 }
379
380 NTSTATUS
381 STDCALL
382 MmCreateProcessAddressSpace(IN PEPROCESS Process,
383 IN PSECTION_OBJECT Section OPTIONAL)
384 {
385 NTSTATUS Status;
386 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
387 PVOID BaseAddress;
388 PMEMORY_AREA MemoryArea;
389 PHYSICAL_ADDRESS BoundaryAddressMultiple;
390 ULONG ViewSize = 0;
391 PVOID ImageBase = 0;
392 BoundaryAddressMultiple.QuadPart = 0;
393
394 /* Initialize the Addresss Space */
395 MmInitializeAddressSpace(Process, ProcessAddressSpace);
396
397 /* Acquire the Lock */
398 MmLockAddressSpace(ProcessAddressSpace);
399
400 /* Protect the highest 64KB of the process address space */
401 BaseAddress = (PVOID)MmUserProbeAddress;
402 Status = MmCreateMemoryArea(Process,
403 ProcessAddressSpace,
404 MEMORY_AREA_NO_ACCESS,
405 &BaseAddress,
406 0x10000,
407 PAGE_NOACCESS,
408 &MemoryArea,
409 FALSE,
410 FALSE,
411 BoundaryAddressMultiple);
412 if (!NT_SUCCESS(Status))
413 {
414 DPRINT1("Failed to protect last 64KB\n");
415 goto exit;
416 }
417
418 /* Protect the 60KB above the shared user page */
419 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
420 Status = MmCreateMemoryArea(Process,
421 ProcessAddressSpace,
422 MEMORY_AREA_NO_ACCESS,
423 &BaseAddress,
424 0x10000 - PAGE_SIZE,
425 PAGE_NOACCESS,
426 &MemoryArea,
427 FALSE,
428 FALSE,
429 BoundaryAddressMultiple);
430 if (!NT_SUCCESS(Status))
431 {
432 DPRINT1("Failed to protect the memory above the shared user page\n");
433 goto exit;
434 }
435
436 /* Create the shared data page */
437 BaseAddress = (PVOID)USER_SHARED_DATA;
438 Status = MmCreateMemoryArea(Process,
439 ProcessAddressSpace,
440 MEMORY_AREA_SHARED_DATA,
441 &BaseAddress,
442 PAGE_SIZE,
443 PAGE_READONLY,
444 &MemoryArea,
445 FALSE,
446 FALSE,
447 BoundaryAddressMultiple);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT1("Failed to create Shared User Data\n");
451 goto exit;
452 }
453
454 /* Check if there's a Section Object */
455 if (Section)
456 {
457 UNICODE_STRING FileName;
458 PWCHAR szSrc;
459 PCHAR szDest;
460 USHORT lnFName = 0;
461
462 /* Unlock the Address Space */
463 DPRINT("Unlocking\n");
464 MmUnlockAddressSpace(ProcessAddressSpace);
465
466 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
467 Section, Process, &ImageBase);
468 Status = MmMapViewOfSection(Section,
469 Process,
470 (PVOID*)&ImageBase,
471 0,
472 0,
473 NULL,
474 &ViewSize,
475 0,
476 MEM_COMMIT,
477 PAGE_READWRITE);
478 if (!NT_SUCCESS(Status))
479 {
480 DPRINT1("Failed to map process Image\n");
481 goto exit;
482 }
483
484 /* Save the pointer */
485 Process->SectionBaseAddress = ImageBase;
486
487 /* Determine the image file name and save it to EPROCESS */
488 DPRINT("Getting Image name\n");
489 FileName = Section->FileObject->FileName;
490 szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
491
492 while(szSrc >= FileName.Buffer)
493 {
494 if(*szSrc == L'\\')
495 {
496 szSrc++;
497 break;
498 }
499 else
500 {
501 szSrc--;
502 lnFName++;
503 }
504 }
505
506 /* Copy the to the process and truncate it to 15 characters if necessary */
507 DPRINT("Copying and truncating\n");
508 szDest = Process->ImageFileName;
509 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
510 while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
511
512 /* Return status to caller */
513 return Status;
514 }
515
516 exit:
517 /* Unlock the Address Space */
518 DPRINT("Unlocking\n");
519 MmUnlockAddressSpace(ProcessAddressSpace);
520
521 /* Return status to caller */
522 return Status;
523 }