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