Used MmFreeVirtualMemory in MmDeleteTeb because MmFreeMemoryAreaByPtr doesn't free...
[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 /* Map NLS Tables */
207 DPRINT("Mapping NLS\n");
208 Status = MmMapViewOfSection(NlsSectionObject,
209 Process,
210 &TableBase,
211 0,
212 0,
213 &SectionOffset,
214 &ViewSize,
215 ViewShare,
216 MEM_TOP_DOWN,
217 PAGE_READONLY);
218 if (!NT_SUCCESS(Status))
219 {
220 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
221 return(Status);
222 }
223 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
224
225 /* Attach to Process */
226 KeAttachProcess(&Process->Pcb);
227
228 /* Allocate the PEB */
229 Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE);
230
231 /* Initialize the PEB */
232 DPRINT("Allocated: %x\n", Peb);
233 RtlZeroMemory(Peb, sizeof(PEB));
234
235 /* Set up data */
236 DPRINT("Setting up PEB\n");
237 Peb->ImageBaseAddress = Process->SectionBaseAddress;
238 Peb->InheritedAddressSpace = 0;
239 Peb->Mutant = NULL;
240
241 /* NLS */
242 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
243 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
244 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
245
246 /* Default Version Data (could get changed below) */
247 Peb->OSMajorVersion = NtMajorVersion;
248 Peb->OSMinorVersion = NtMinorVersion;
249 Peb->OSBuildNumber = 2195;
250 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
251 Peb->OSCSDVersion = NtOSCSDVersion;
252
253 /* Heap and Debug Data */
254 Peb->NumberOfProcessors = KeNumberProcessors;
255 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
256 Peb->NtGlobalFlag = NtGlobalFlag;
257 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
258 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
259 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
260 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
261 Peb->NumberOfHeaps = 0;
262 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
263 Peb->ProcessHeaps = (PVOID*)Peb + 1;
264
265 /* Image Data */
266 if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
267 {
268 /* Get the Image Config Data too */
269 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
270 TRUE,
271 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
272 &ViewSize);
273
274 /* Write subsystem data */
275 Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
276 Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
277 Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
278
279 /* Write Version Data */
280 if (NtHeaders->OptionalHeader.Win32VersionValue)
281 {
282 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
283 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
284 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
285
286 /* Lie about the version if requested */
287 if (ImageConfigData && ImageConfigData->CSDVersion)
288 {
289 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
290 }
291
292 /* Set the Platform ID */
293 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
294 }
295
296 /* Check for affinity override */
297 if (ImageConfigData && ImageConfigData->ProcessAffinityMask)
298 {
299 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
300 }
301
302 /* Check if the image is not safe for SMP */
303 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
304 {
305 /* FIXME: Choose one randomly */
306 Peb->ImageProcessAffinityMask = 1;
307 }
308 else
309 {
310 /* Use affinity from Image Header */
311 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
312 }
313 }
314
315 /* Misc data */
316 Peb->SessionId = Process->Session;
317 Process->Peb = Peb;
318
319 /* Detach from the Process */
320 KeDetachProcess();
321
322 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
323 return STATUS_SUCCESS;
324 }
325
326 PTEB
327 STDCALL
328 MmCreateTeb(PEPROCESS Process,
329 PCLIENT_ID ClientId,
330 PINITIAL_TEB InitialTeb)
331 {
332 PTEB Teb;
333 BOOLEAN Attached = FALSE;
334
335 /* Attach to the process */
336 DPRINT("MmCreateTeb\n");
337 if (Process != PsGetCurrentProcess())
338 {
339 /* Attach to Target */
340 KeAttachProcess(&Process->Pcb);
341 Attached = TRUE;
342 }
343
344 /* Allocate the TEB */
345 Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE);
346
347 /* Initialize the PEB */
348 RtlZeroMemory(Teb, sizeof(TEB));
349
350 /* Set TIB Data */
351 Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
352 Teb->Tib.Version = 1;
353 Teb->Tib.Self = (PNT_TIB)Teb;
354
355 /* Set TEB Data */
356 Teb->Cid = *ClientId;
357 Teb->RealClientId = *ClientId;
358 Teb->ProcessEnvironmentBlock = Process->Peb;
359 Teb->CurrentLocale = PsDefaultThreadLocaleId;
360
361 /* Store stack information from InitialTeb */
362 if(InitialTeb != NULL)
363 {
364 Teb->Tib.StackBase = InitialTeb->StackBase;
365 Teb->Tib.StackLimit = InitialTeb->StackLimit;
366 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
367 }
368
369 /* Return TEB Address */
370 DPRINT("Allocated: %x\n", Teb);
371 if (Attached) KeDetachProcess();
372 return Teb;
373 }
374
375 NTSTATUS
376 STDCALL
377 MmCreateProcessAddressSpace(IN PEPROCESS Process,
378 IN PSECTION_OBJECT Section OPTIONAL)
379 {
380 NTSTATUS Status;
381 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
382 PVOID BaseAddress;
383 PMEMORY_AREA MemoryArea;
384 PHYSICAL_ADDRESS BoundaryAddressMultiple;
385 ULONG ViewSize = 0;
386 PVOID ImageBase = 0;
387 BoundaryAddressMultiple.QuadPart = 0;
388
389 /* Initialize the Addresss Space */
390 MmInitializeAddressSpace(Process, ProcessAddressSpace);
391
392 /* Acquire the Lock */
393 MmLockAddressSpace(ProcessAddressSpace);
394
395 /* Protect the highest 64KB of the process address space */
396 BaseAddress = (PVOID)MmUserProbeAddress;
397 Status = MmCreateMemoryArea(Process,
398 ProcessAddressSpace,
399 MEMORY_AREA_NO_ACCESS,
400 &BaseAddress,
401 0x10000,
402 PAGE_NOACCESS,
403 &MemoryArea,
404 FALSE,
405 FALSE,
406 BoundaryAddressMultiple);
407 if (!NT_SUCCESS(Status))
408 {
409 DPRINT1("Failed to protect last 64KB\n");
410 goto exit;
411 }
412
413 /* Protect the 60KB above the shared user page */
414 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
415 Status = MmCreateMemoryArea(Process,
416 ProcessAddressSpace,
417 MEMORY_AREA_NO_ACCESS,
418 &BaseAddress,
419 0x10000 - PAGE_SIZE,
420 PAGE_NOACCESS,
421 &MemoryArea,
422 FALSE,
423 FALSE,
424 BoundaryAddressMultiple);
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("Failed to protect the memory above the shared user page\n");
428 goto exit;
429 }
430
431 /* Create the shared data page */
432 BaseAddress = (PVOID)USER_SHARED_DATA;
433 Status = MmCreateMemoryArea(Process,
434 ProcessAddressSpace,
435 MEMORY_AREA_SHARED_DATA,
436 &BaseAddress,
437 PAGE_SIZE,
438 PAGE_READONLY,
439 &MemoryArea,
440 FALSE,
441 FALSE,
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 ObDereferenceObject(Section);
477 goto exit;
478 }
479 ObDereferenceObject(Section);
480
481 /* Save the pointer */
482 Process->SectionBaseAddress = ImageBase;
483
484 /* Determine the image file name and save it to EPROCESS */
485 DPRINT("Getting Image name\n");
486 FileName = Section->FileObject->FileName;
487 szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
488
489 while(szSrc >= FileName.Buffer)
490 {
491 if(*szSrc == L'\\')
492 {
493 szSrc++;
494 break;
495 }
496 else
497 {
498 szSrc--;
499 lnFName++;
500 }
501 }
502
503 /* Copy the to the process and truncate it to 15 characters if necessary */
504 DPRINT("Copying and truncating\n");
505 szDest = Process->ImageFileName;
506 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
507 while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
508
509 /* Return status to caller */
510 return Status;
511 }
512
513 exit:
514 /* Unlock the Address Space */
515 DPRINT("Unlocking\n");
516 MmUnlockAddressSpace(ProcessAddressSpace);
517
518 /* Return status to caller */
519 return Status;
520 }