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