Merge amd64 NDK from amd64 branch:
[reactos.git] / reactos / ntoskrnl / mm / procsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/procsup.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 <debug.h>
15
16 extern ULONG NtMajorVersion;
17 extern ULONG NtMinorVersion;
18 extern ULONG CmNtCSDVersion;
19 extern ULONG NtBuildNumber;
20 extern MM_SYSTEMSIZE MmSystemSize;
21
22 #define MM_HIGHEST_VAD_ADDRESS \
23 (PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
24
25 /* FUNCTIONS *****************************************************************/
26
27 NTSTATUS
28 NTAPI
29 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
30 IN UCHAR MemoryPriority)
31 {
32 UCHAR OldPriority;
33
34 /* Check if we have less then 16MB of Physical Memory */
35 if ((MmSystemSize == MmSmallSystem) &&
36 (MmStats.NrTotalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
37 {
38 /* Always use background priority */
39 MemoryPriority = 0;
40 }
41
42 /* Save the old priority and update it */
43 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
44 Process->Vm.Flags.MemoryPriority = MemoryPriority;
45
46 /* Return the old priority */
47 return OldPriority;
48 }
49
50 LCID
51 NTAPI
52 MmGetSessionLocaleId(VOID)
53 {
54 PEPROCESS Process;
55 PAGED_CODE();
56
57 /* Get the current process */
58 Process = PsGetCurrentProcess();
59
60 /* Check if it's the Session Leader */
61 if (Process->Vm.Flags.SessionLeader)
62 {
63 /* Make sure it has a valid Session */
64 if (Process->Session)
65 {
66 /* Get the Locale ID */
67 #if ROS_HAS_SESSIONS
68 return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
69 #endif
70 }
71 }
72
73 /* Not a session leader, return the default */
74 return PsDefaultThreadLocaleId;
75 }
76
77 PVOID
78 NTAPI
79 MiCreatePebOrTeb(PEPROCESS Process,
80 PVOID BaseAddress)
81 {
82 NTSTATUS Status;
83 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
84 PMEMORY_AREA MemoryArea;
85 PHYSICAL_ADDRESS BoundaryAddressMultiple;
86 PVOID AllocatedBase = BaseAddress;
87 BoundaryAddressMultiple.QuadPart = 0;
88
89 /* Acquire the Lock */
90 MmLockAddressSpace(ProcessAddressSpace);
91
92 /*
93 * Create a Peb or Teb.
94 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
95 * is that a PEB allocation should never fail since the address is free,
96 * while TEB allocation can fail, and we should simply try the address
97 * below. Is there a nicer way of doing this automagically? (ie: findning)
98 * a gap region? -- Alex
99 */
100 do {
101 DPRINT("Trying to allocate: %x\n", AllocatedBase);
102 Status = MmCreateMemoryArea(ProcessAddressSpace,
103 MEMORY_AREA_PEB_OR_TEB,
104 &AllocatedBase,
105 PAGE_SIZE,
106 PAGE_READWRITE,
107 &MemoryArea,
108 TRUE,
109 0,
110 BoundaryAddressMultiple);
111 AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
112 } while (Status != STATUS_SUCCESS);
113
114 /* Initialize the Region */
115 MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
116 PAGE_SIZE,
117 MEM_COMMIT,
118 PAGE_READWRITE);
119
120 /* Reserve the pages */
121 MmReserveSwapPages(PAGE_SIZE);
122
123 /* Unlock Address Space */
124 DPRINT("Returning\n");
125 MmUnlockAddressSpace(ProcessAddressSpace);
126 return RVA(AllocatedBase, PAGE_SIZE);
127 }
128
129 VOID
130 NTAPI
131 MmDeleteTeb(PEPROCESS Process,
132 PTEB Teb)
133 {
134 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
135 PMEMORY_AREA MemoryArea;
136
137 /* Lock the Address Space */
138 MmLockAddressSpace(ProcessAddressSpace);
139
140 MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
141 if (MemoryArea)
142 {
143 /* Delete the Teb */
144 MmFreeVirtualMemory(Process, MemoryArea);
145 }
146
147 /* Unlock the Address Space */
148 MmUnlockAddressSpace(ProcessAddressSpace);
149 }
150
151 NTSTATUS
152 NTAPI
153 MmCreatePeb(PEPROCESS Process)
154 {
155 PPEB Peb = NULL;
156 LARGE_INTEGER SectionOffset;
157 SIZE_T ViewSize = 0;
158 PVOID TableBase = NULL;
159 PIMAGE_NT_HEADERS NtHeaders;
160 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
161 NTSTATUS Status;
162 KAFFINITY ProcessAffinityMask = 0;
163 SectionOffset.QuadPart = (ULONGLONG)0;
164 DPRINT("MmCreatePeb\n");
165
166 /* Allocate the PEB */
167 Peb = MiCreatePebOrTeb(Process,
168 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
169 ASSERT(Peb == (PVOID)0x7FFDF000);
170
171 /* Map NLS Tables */
172 DPRINT("Mapping NLS\n");
173 Status = MmMapViewOfSection(ExpNlsSectionPointer,
174 (PEPROCESS)Process,
175 &TableBase,
176 0,
177 0,
178 &SectionOffset,
179 &ViewSize,
180 ViewShare,
181 MEM_TOP_DOWN,
182 PAGE_READONLY);
183 if (!NT_SUCCESS(Status))
184 {
185 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
186 return(Status);
187 }
188 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
189
190 /* Attach to Process */
191 KeAttachProcess(&Process->Pcb);
192
193 /* Initialize the PEB */
194 DPRINT("Allocated: %x\n", Peb);
195 RtlZeroMemory(Peb, sizeof(PEB));
196
197 /* Set up data */
198 DPRINT("Setting up PEB\n");
199 Peb->ImageBaseAddress = Process->SectionBaseAddress;
200 Peb->InheritedAddressSpace = 0;
201 Peb->Mutant = NULL;
202
203 /* NLS */
204 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
205 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
206 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
207
208 /* Default Version Data (could get changed below) */
209 Peb->OSMajorVersion = NtMajorVersion;
210 Peb->OSMinorVersion = NtMinorVersion;
211 Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
212 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
213 Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
214
215 /* Heap and Debug Data */
216 Peb->NumberOfProcessors = KeNumberProcessors;
217 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
218 Peb->NtGlobalFlag = NtGlobalFlag;
219 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
220 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
221 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
222 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
223 Peb->NumberOfHeaps = 0;
224 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
225 Peb->ProcessHeaps = (PVOID*)(Peb + 1);
226
227 /* Image Data */
228 if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
229 {
230 /* Write subsystem data */
231 Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
232 Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
233 Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
234
235 /* Write Version Data */
236 if (NtHeaders->OptionalHeader.Win32VersionValue)
237 {
238 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
239 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
240 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
241
242 /* Set the Platform ID */
243 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
244 }
245
246 /* Check if the image is not safe for SMP */
247 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
248 {
249 /* FIXME: Choose one randomly */
250 Peb->ImageProcessAffinityMask = 1;
251 }
252 else
253 {
254 /* Use affinity from Image Header */
255 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
256 }
257
258 _SEH2_TRY
259 {
260 /* Get the Image Config Data too */
261 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
262 TRUE,
263 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
264 &ViewSize);
265
266 ProbeForRead(ImageConfigData,
267 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
268 sizeof(ULONG));
269
270 /* Process the image config data overrides if specfied. */
271 if (ImageConfigData != NULL)
272 {
273 if (ImageConfigData->CSDVersion)
274 {
275 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
276 }
277 if (ImageConfigData->ProcessAffinityMask)
278 {
279 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
280 }
281 }
282 }
283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
284 {
285 Status = _SEH2_GetExceptionCode();
286 }
287 _SEH2_END;
288 }
289
290 /* Misc data */
291 Peb->SessionId = Process->Session;
292 Process->Peb = Peb;
293
294 /* Detach from the Process */
295 KeDetachProcess();
296
297 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
298 return Status;
299 }
300
301 PTEB
302 NTAPI
303 MmCreateTeb(PEPROCESS Process,
304 PCLIENT_ID ClientId,
305 PINITIAL_TEB InitialTeb)
306 {
307 PTEB Teb;
308 BOOLEAN Attached = FALSE;
309
310 /* Attach to the process */
311 DPRINT("MmCreateTeb\n");
312 if (Process != PsGetCurrentProcess())
313 {
314 /* Attach to Target */
315 KeAttachProcess(&Process->Pcb);
316 Attached = TRUE;
317 }
318
319 /* Allocate the TEB */
320 Teb = MiCreatePebOrTeb(Process,
321 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
322
323 /* Initialize the PEB */
324 RtlZeroMemory(Teb, sizeof(TEB));
325
326 /* Set TIB Data */
327 Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
328 Teb->Tib.Version = 1;
329 Teb->Tib.Self = (PNT_TIB)Teb;
330
331 /* Set TEB Data */
332 Teb->ClientId = *ClientId;
333 Teb->RealClientId = *ClientId;
334 Teb->ProcessEnvironmentBlock = Process->Peb;
335 Teb->CurrentLocale = PsDefaultThreadLocaleId;
336
337 /* Store stack information from InitialTeb */
338 if(InitialTeb != NULL)
339 {
340 Teb->Tib.StackBase = InitialTeb->StackBase;
341 Teb->Tib.StackLimit = InitialTeb->StackLimit;
342 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
343 }
344
345 /* Initialize the static unicode string */
346 Teb->StaticUnicodeString.Length = 0;
347 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
348 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
349
350 /* Return TEB Address */
351 DPRINT("Allocated: %x\n", Teb);
352 if (Attached) KeDetachProcess();
353 return Teb;
354 }
355
356 NTSTATUS
357 NTAPI
358 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
359 {
360 PVOID BaseAddress;
361 PMEMORY_AREA MemoryArea;
362 PHYSICAL_ADDRESS BoundaryAddressMultiple;
363 NTSTATUS Status;
364 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
365 BoundaryAddressMultiple.QuadPart = 0;
366
367 /* Create the shared data page */
368 BaseAddress = (PVOID)USER_SHARED_DATA;
369 Status = MmCreateMemoryArea(ProcessAddressSpace,
370 MEMORY_AREA_SHARED_DATA,
371 &BaseAddress,
372 PAGE_SIZE,
373 PAGE_EXECUTE_READ,
374 &MemoryArea,
375 FALSE,
376 0,
377 BoundaryAddressMultiple);
378 return Status;
379 }
380
381 NTSTATUS
382 NTAPI
383 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
384 IN PEPROCESS ProcessClone OPTIONAL,
385 IN PVOID Section OPTIONAL,
386 IN OUT PULONG Flags,
387 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
388 {
389 NTSTATUS Status;
390 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
391 PVOID BaseAddress;
392 PMEMORY_AREA MemoryArea;
393 PHYSICAL_ADDRESS BoundaryAddressMultiple;
394 SIZE_T ViewSize = 0;
395 PVOID ImageBase = 0;
396 PROS_SECTION_OBJECT SectionObject = Section;
397 BoundaryAddressMultiple.QuadPart = 0;
398
399 /* Initialize the Addresss Space lock */
400 KeInitializeGuardedMutex(&Process->AddressCreationLock);
401 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
402
403 /* Initialize AVL tree */
404 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
405 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
406
407 /* Acquire the Lock */
408 MmLockAddressSpace(ProcessAddressSpace);
409
410 /* Protect the highest 64KB of the process address space */
411 BaseAddress = (PVOID)MmUserProbeAddress;
412 Status = MmCreateMemoryArea(ProcessAddressSpace,
413 MEMORY_AREA_NO_ACCESS,
414 &BaseAddress,
415 0x10000,
416 PAGE_NOACCESS,
417 &MemoryArea,
418 FALSE,
419 0,
420 BoundaryAddressMultiple);
421 if (!NT_SUCCESS(Status))
422 {
423 DPRINT1("Failed to protect last 64KB\n");
424 goto exit;
425 }
426
427 /* Protect the 60KB above the shared user page */
428 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
429 Status = MmCreateMemoryArea(ProcessAddressSpace,
430 MEMORY_AREA_NO_ACCESS,
431 &BaseAddress,
432 0x10000 - PAGE_SIZE,
433 PAGE_NOACCESS,
434 &MemoryArea,
435 FALSE,
436 0,
437 BoundaryAddressMultiple);
438 if (!NT_SUCCESS(Status))
439 {
440 DPRINT1("Failed to protect the memory above the shared user page\n");
441 goto exit;
442 }
443
444 /* Create the shared data page */
445 BaseAddress = (PVOID)USER_SHARED_DATA;
446 Status = MmCreateMemoryArea(ProcessAddressSpace,
447 MEMORY_AREA_SHARED_DATA,
448 &BaseAddress,
449 PAGE_SIZE,
450 PAGE_EXECUTE_READ,
451 &MemoryArea,
452 FALSE,
453 0,
454 BoundaryAddressMultiple);
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT1("Failed to create Shared User Data\n");
458 goto exit;
459 }
460
461 /* The process now has an address space */
462 Process->HasAddressSpace = TRUE;
463
464 /* Check if there's a Section Object */
465 if (SectionObject)
466 {
467 UNICODE_STRING FileName;
468 PWCHAR szSrc;
469 PCHAR szDest;
470 USHORT lnFName = 0;
471
472 /* Unlock the Address Space */
473 DPRINT("Unlocking\n");
474 MmUnlockAddressSpace(ProcessAddressSpace);
475
476 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
477 SectionObject, Process, &ImageBase);
478 Status = MmMapViewOfSection(Section,
479 (PEPROCESS)Process,
480 (PVOID*)&ImageBase,
481 0,
482 0,
483 NULL,
484 &ViewSize,
485 0,
486 MEM_COMMIT,
487 PAGE_READWRITE);
488 if (!NT_SUCCESS(Status))
489 {
490 DPRINT1("Failed to map process Image\n");
491 return Status;
492 }
493
494 /* Save the pointer */
495 Process->SectionBaseAddress = ImageBase;
496
497 /* Determine the image file name and save it to EPROCESS */
498 DPRINT("Getting Image name\n");
499 FileName = SectionObject->FileObject->FileName;
500 szSrc = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
501 if (FileName.Buffer)
502 {
503 /* Loop the file name*/
504 while (szSrc > FileName.Buffer)
505 {
506 /* Make sure this isn't a backslash */
507 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
508 {
509 /* If so, stop it here */
510 szSrc++;
511 break;
512 }
513 else
514 {
515 /* Otherwise, keep going */
516 lnFName++;
517 }
518 }
519 }
520
521 /* Copy the to the process and truncate it to 15 characters if necessary */
522 szDest = Process->ImageFileName;
523 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
524 while (lnFName--) *szDest++ = (UCHAR)*szSrc++;
525 *szDest = ANSI_NULL;
526
527 /* Check if caller wants an audit name */
528 if (AuditName)
529 {
530 /* Setup the audit name */
531 SeInitializeProcessAuditName(SectionObject->FileObject,
532 FALSE,
533 AuditName);
534 }
535
536 /* Return status to caller */
537 return Status;
538 }
539
540 exit:
541 /* Unlock the Address Space */
542 DPRINT("Unlocking\n");
543 MmUnlockAddressSpace(ProcessAddressSpace);
544
545 /* Return status to caller */
546 return Status;
547 }
548
549 VOID
550 NTAPI
551 MmCleanProcessAddressSpace(IN PEPROCESS Process)
552 {
553 /* FIXME: Add part of MmDeleteProcessAddressSpace here */
554 }
555
556 NTSTATUS
557 NTAPI
558 MmDeleteProcessAddressSpace(PEPROCESS Process)
559 {
560 PVOID Address;
561 PMEMORY_AREA MemoryArea;
562
563 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
564 Process->ImageFileName);
565
566 MmLockAddressSpace(&Process->Vm);
567
568 while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
569 {
570 switch (MemoryArea->Type)
571 {
572 case MEMORY_AREA_SECTION_VIEW:
573 Address = (PVOID)MemoryArea->StartingAddress;
574 MmUnlockAddressSpace(&Process->Vm);
575 MmUnmapViewOfSection(Process, Address);
576 MmLockAddressSpace(&Process->Vm);
577 break;
578
579 case MEMORY_AREA_VIRTUAL_MEMORY:
580 case MEMORY_AREA_PEB_OR_TEB:
581 MmFreeVirtualMemory(Process, MemoryArea);
582 break;
583
584 case MEMORY_AREA_SHARED_DATA:
585 case MEMORY_AREA_NO_ACCESS:
586 MmFreeMemoryArea(&Process->Vm,
587 MemoryArea,
588 NULL,
589 NULL);
590 break;
591
592 case MEMORY_AREA_MDL_MAPPING:
593 KeBugCheck(PROCESS_HAS_LOCKED_PAGES);
594 break;
595
596 default:
597 KeBugCheck(MEMORY_MANAGEMENT);
598 }
599 }
600
601 Mmi386ReleaseMmInfo(Process);
602
603 MmUnlockAddressSpace(&Process->Vm);
604
605 DPRINT("Finished MmReleaseMmInfo()\n");
606 return(STATUS_SUCCESS);
607 }
608