Fix boot regression.
[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 DPRINT("MmCreatePeb\n");
205
206 /* Allocate the PEB */
207 Peb = MiCreatePebOrTeb(Process,
208 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
209 ASSERT(Peb == (PVOID)0x7FFDF000)
210
211 /* Map NLS Tables */
212 DPRINT("Mapping NLS\n");
213 Status = MmMapViewOfSection(NlsSectionObject,
214 Process,
215 &TableBase,
216 0,
217 0,
218 &SectionOffset,
219 &ViewSize,
220 ViewShare,
221 MEM_TOP_DOWN,
222 PAGE_READONLY);
223 if (!NT_SUCCESS(Status))
224 {
225 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
226 return(Status);
227 }
228 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
229
230 /* Attach to Process */
231 KeAttachProcess(&Process->Pcb);
232
233 /* Initialize the PEB */
234 DPRINT("Allocated: %x\n", Peb);
235 RtlZeroMemory(Peb, sizeof(PEB));
236
237 /* Set up data */
238 DPRINT("Setting up PEB\n");
239 Peb->ImageBaseAddress = Process->SectionBaseAddress;
240 Peb->InheritedAddressSpace = 0;
241 Peb->Mutant = NULL;
242
243 /* NLS */
244 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
245 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
246 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
247
248 /* Default Version Data (could get changed below) */
249 Peb->OSMajorVersion = NtMajorVersion;
250 Peb->OSMinorVersion = NtMinorVersion;
251 Peb->OSBuildNumber = 2195;
252 Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
253 Peb->OSCSDVersion = NtOSCSDVersion;
254
255 /* Heap and Debug Data */
256 Peb->NumberOfProcessors = KeNumberProcessors;
257 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
258 Peb->NtGlobalFlag = NtGlobalFlag;
259 /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
260 Peb->HeapSegmentCommit = MmHeapSegmentCommit;
261 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
262 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/
263 Peb->NumberOfHeaps = 0;
264 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
265 Peb->ProcessHeaps = (PVOID*)Peb + 1;
266
267 /* Image Data */
268 if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress)))
269 {
270 /* Get the Image Config Data too */
271 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
272 TRUE,
273 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
274 &ViewSize);
275
276 /* Write subsystem data */
277 Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem;
278 Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
279 Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
280
281 /* Write Version Data */
282 if (NtHeaders->OptionalHeader.Win32VersionValue)
283 {
284 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
285 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
286 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
287
288 /* Lie about the version if requested */
289 if (ImageConfigData && ImageConfigData->CSDVersion)
290 {
291 Peb->OSCSDVersion = ImageConfigData->CSDVersion;
292 }
293
294 /* Set the Platform ID */
295 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
296 }
297
298 /* Check for affinity override */
299 if (ImageConfigData && ImageConfigData->ProcessAffinityMask)
300 {
301 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
302 }
303
304 /* Check if the image is not safe for SMP */
305 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
306 {
307 /* FIXME: Choose one randomly */
308 Peb->ImageProcessAffinityMask = 1;
309 }
310 else
311 {
312 /* Use affinity from Image Header */
313 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
314 }
315 }
316
317 /* Misc data */
318 Peb->SessionId = Process->Session;
319 Process->Peb = Peb;
320
321 /* Detach from the Process */
322 KeDetachProcess();
323
324 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
325 return STATUS_SUCCESS;
326 }
327
328 PTEB
329 STDCALL
330 MmCreateTeb(PEPROCESS Process,
331 PCLIENT_ID ClientId,
332 PINITIAL_TEB InitialTeb)
333 {
334 PTEB Teb;
335 BOOLEAN Attached = FALSE;
336
337 /* Attach to the process */
338 DPRINT("MmCreateTeb\n");
339 if (Process != PsGetCurrentProcess())
340 {
341 /* Attach to Target */
342 KeAttachProcess(&Process->Pcb);
343 Attached = TRUE;
344 }
345
346 /* Allocate the TEB */
347 Teb = MiCreatePebOrTeb(Process,
348 (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
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 }