b74f4f1f183bfd25ceeb5ac4ac4d82aceb4fa564
[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
20 /* FUNCTIONS *****************************************************************/
21
22 PVOID
23 STDCALL
24 MiCreatePebOrTeb(PEPROCESS Process,
25 PVOID BaseAddress)
26 {
27 NTSTATUS Status;
28 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
29 PMEMORY_AREA MemoryArea;
30 PHYSICAL_ADDRESS BoundaryAddressMultiple;
31 PVOID AllocatedBase = BaseAddress;
32 BoundaryAddressMultiple.QuadPart = 0;
33
34 /* Acquire the Lock */
35 MmLockAddressSpace(ProcessAddressSpace);
36
37 /*
38 * Create a Peb or Teb.
39 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
40 * is that a PEB allocation should never fail since the address is free,
41 * while TEB allocation can fail, and we should simply try the address
42 * below. Is there a nicer way of doing this automagically? (ie: findning)
43 * a gap region? -- Alex
44 */
45 do {
46 DPRINT("Trying to allocate: %x\n", AllocatedBase);
47 Status = MmCreateMemoryArea(Process,
48 ProcessAddressSpace,
49 MEMORY_AREA_PEB_OR_TEB,
50 &AllocatedBase,
51 PAGE_SIZE,
52 PAGE_READWRITE,
53 &MemoryArea,
54 TRUE,
55 FALSE,
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 MiFreePebPage(PVOID Context,
107 MEMORY_AREA* MemoryArea,
108 PVOID Address,
109 PFN_TYPE Page,
110 SWAPENTRY SwapEntry,
111 BOOLEAN Dirty)
112 {
113 PEPROCESS Process = (PEPROCESS)Context;
114
115 if (Page != 0)
116 {
117 SWAPENTRY SavedSwapEntry;
118 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
119 if (SavedSwapEntry != 0)
120 {
121 MmFreeSwapPage(SavedSwapEntry);
122 MmSetSavedSwapEntryPage(Page, 0);
123 }
124 MmDeleteRmap(Page, Process, Address);
125 MmReleasePageMemoryConsumer(MC_USER, Page);
126 }
127 else if (SwapEntry != 0)
128 {
129 MmFreeSwapPage(SwapEntry);
130 }
131 }
132
133 VOID
134 STDCALL
135 MmDeleteTeb(PEPROCESS Process,
136 PTEB Teb)
137 {
138 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
139
140 /* Lock the Address Space */
141 MmLockAddressSpace(ProcessAddressSpace);
142
143 /* Delete the Stack */
144 MmFreeMemoryAreaByPtr(ProcessAddressSpace,
145 Teb,
146 MiFreePebPage,
147 Process);
148
149 /* Unlock the Address Space */
150 MmUnlockAddressSpace(ProcessAddressSpace);
151 }
152
153 PVOID
154 STDCALL
155 MmCreateKernelStack(BOOLEAN GuiStack)
156 {
157 PMEMORY_AREA StackArea;
158 ULONG i;
159 PHYSICAL_ADDRESS BoundaryAddressMultiple;
160 PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
161 PVOID KernelStack = NULL;
162 NTSTATUS Status;
163
164 /* Initialize the Boundary Address */
165 BoundaryAddressMultiple.QuadPart = 0;
166
167 /* Lock the Kernel Address Space */
168 MmLockAddressSpace(MmGetKernelAddressSpace());
169
170 /* Create a MAREA for the Kernel Stack */
171 Status = MmCreateMemoryArea(NULL,
172 MmGetKernelAddressSpace(),
173 MEMORY_AREA_KERNEL_STACK,
174 &KernelStack,
175 MM_STACK_SIZE,
176 0,
177 &StackArea,
178 FALSE,
179 FALSE,
180 BoundaryAddressMultiple);
181
182 /* Unlock the Address Space */
183 MmUnlockAddressSpace(MmGetKernelAddressSpace());
184
185 /* Check for Success */
186 if (!NT_SUCCESS(Status))
187 {
188 DPRINT1("Failed to create thread stack\n");
189 KEBUGCHECK(0);
190 }
191
192 /* Mark the Stack in use */
193 for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
194 {
195 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
196 }
197
198 /* Create a Virtual Mapping for it */
199 Status = MmCreateVirtualMapping(NULL,
200 KernelStack,
201 PAGE_READWRITE,
202 Page,
203 MM_STACK_SIZE / PAGE_SIZE);
204
205 /* Check for success */
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
209 KEBUGCHECK(0);
210 }
211
212 return KernelStack;
213 }
214
215 NTSTATUS
216 STDCALL
217 MmCreatePeb(PEPROCESS Process)
218 {
219 PPEB Peb = NULL;
220 LARGE_INTEGER SectionOffset;
221 ULONG ViewSize = 0;
222 PVOID TableBase = NULL;
223 NTSTATUS Status;
224 SectionOffset.QuadPart = (ULONGLONG)0;
225
226 DPRINT("MmCreatePeb\n");
227
228 /* Map NLS Tables */
229 DPRINT("Mapping NLS\n");
230 Status = MmMapViewOfSection(NlsSectionObject,
231 Process,
232 &TableBase,
233 0,
234 0,
235 &SectionOffset,
236 &ViewSize,
237 ViewShare,
238 MEM_TOP_DOWN,
239 PAGE_READONLY);
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
243 return(Status);
244 }
245 DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
246
247 /* Attach to Process */
248 KeAttachProcess(&Process->Pcb);
249
250 /* Allocate the PEB */
251 Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE);
252
253 /* Initialize the PEB */
254 DPRINT("Allocated: %x\n", Peb);
255 RtlZeroMemory(Peb, sizeof(PEB));
256
257 /* Set up data */
258 DPRINT("Setting up PEB\n");
259 Peb->ImageBaseAddress = Process->SectionBaseAddress;
260 Peb->OSMajorVersion = NtMajorVersion;
261 Peb->OSMinorVersion = NtMinorVersion;
262 Peb->OSBuildNumber = 2195;
263 Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
264 Peb->OSCSDVersion = NtOSCSDVersion;
265 Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
266 Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
267 Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
268 Peb->NumberOfProcessors = KeNumberProcessors;
269 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
270
271 Process->Peb = Peb;
272 KeDetachProcess();
273
274 DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
275 return STATUS_SUCCESS;
276 }
277
278 PTEB
279 STDCALL
280 MmCreateTeb(PEPROCESS Process,
281 PCLIENT_ID ClientId,
282 PINITIAL_TEB InitialTeb)
283 {
284 PTEB Teb;
285 BOOLEAN Attached = FALSE;
286
287 /* Attach to the process */
288 DPRINT("MmCreateTeb\n");
289 if (Process != PsGetCurrentProcess())
290 {
291 /* Attach to Target */
292 KeAttachProcess(&Process->Pcb);
293 Attached = TRUE;
294 }
295
296 /* Allocate the TEB */
297 Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE);
298
299 /* Initialize the PEB */
300 RtlZeroMemory(Teb, sizeof(TEB));
301
302 /* Set TIB Data */
303 Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
304 Teb->Tib.Version = 1;
305 Teb->Tib.Self = (PNT_TIB)Teb;
306
307 /* Set TEB Data */
308 Teb->Cid = *ClientId;
309 Teb->RealClientId = *ClientId;
310 Teb->ProcessEnvironmentBlock = Process->Peb;
311 Teb->CurrentLocale = PsDefaultThreadLocaleId;
312
313 /* Store stack information from InitialTeb */
314 if(InitialTeb != NULL)
315 {
316 Teb->Tib.StackBase = InitialTeb->StackBase;
317 Teb->Tib.StackLimit = InitialTeb->StackLimit;
318 Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
319 }
320
321 /* Return TEB Address */
322 DPRINT("Allocated: %x\n", Teb);
323 if (Attached) KeDetachProcess();
324 return Teb;
325 }
326
327 NTSTATUS
328 STDCALL
329 MmCreateProcessAddressSpace(IN PEPROCESS Process,
330 IN PSECTION_OBJECT Section OPTIONAL)
331 {
332 NTSTATUS Status;
333 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
334 PVOID BaseAddress;
335 PMEMORY_AREA MemoryArea;
336 PHYSICAL_ADDRESS BoundaryAddressMultiple;
337 ULONG ViewSize = 0;
338 PVOID ImageBase = 0;
339 BoundaryAddressMultiple.QuadPart = 0;
340
341 /* Initialize the Addresss Space */
342 MmInitializeAddressSpace(Process, ProcessAddressSpace);
343
344 /* Acquire the Lock */
345 MmLockAddressSpace(ProcessAddressSpace);
346
347 /* Protect the highest 64KB of the process address space */
348 BaseAddress = (PVOID)MmUserProbeAddress;
349 Status = MmCreateMemoryArea(Process,
350 ProcessAddressSpace,
351 MEMORY_AREA_NO_ACCESS,
352 &BaseAddress,
353 0x10000,
354 PAGE_NOACCESS,
355 &MemoryArea,
356 FALSE,
357 FALSE,
358 BoundaryAddressMultiple);
359 if (!NT_SUCCESS(Status))
360 {
361 DPRINT1("Failed to protect last 64KB\n");
362 goto exit;
363 }
364
365 /* Protect the 60KB above the shared user page */
366 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
367 Status = MmCreateMemoryArea(Process,
368 ProcessAddressSpace,
369 MEMORY_AREA_NO_ACCESS,
370 &BaseAddress,
371 0x10000 - PAGE_SIZE,
372 PAGE_NOACCESS,
373 &MemoryArea,
374 FALSE,
375 FALSE,
376 BoundaryAddressMultiple);
377 if (!NT_SUCCESS(Status))
378 {
379 DPRINT1("Failed to protect the memory above the shared user page\n");
380 goto exit;
381 }
382
383 /* Create the shared data page */
384 BaseAddress = (PVOID)USER_SHARED_DATA;
385 Status = MmCreateMemoryArea(Process,
386 ProcessAddressSpace,
387 MEMORY_AREA_SHARED_DATA,
388 &BaseAddress,
389 PAGE_SIZE,
390 PAGE_READONLY,
391 &MemoryArea,
392 FALSE,
393 FALSE,
394 BoundaryAddressMultiple);
395 if (!NT_SUCCESS(Status))
396 {
397 DPRINT1("Failed to create Shared User Data\n");
398 goto exit;
399 }
400
401 /* Check if there's a Section Object */
402 if (Section)
403 {
404 UNICODE_STRING FileName;
405 PWCHAR szSrc;
406 PCHAR szDest;
407 USHORT lnFName = 0;
408
409 /* Unlock the Address Space */
410 DPRINT("Unlocking\n");
411 MmUnlockAddressSpace(ProcessAddressSpace);
412
413 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
414 Section, Process, &ImageBase);
415 Status = MmMapViewOfSection(Section,
416 Process,
417 (PVOID*)&ImageBase,
418 0,
419 0,
420 NULL,
421 &ViewSize,
422 0,
423 MEM_COMMIT,
424 PAGE_READWRITE);
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("Failed to map process Image\n");
428 ObDereferenceObject(Section);
429 goto exit;
430 }
431 ObDereferenceObject(Section);
432
433 /* Save the pointer */
434 Process->SectionBaseAddress = ImageBase;
435
436 /* Determine the image file name and save it to EPROCESS */
437 DPRINT("Getting Image name\n");
438 FileName = Section->FileObject->FileName;
439 szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
440
441 while(szSrc >= FileName.Buffer)
442 {
443 if(*szSrc == L'\\')
444 {
445 szSrc++;
446 break;
447 }
448 else
449 {
450 szSrc--;
451 lnFName++;
452 }
453 }
454
455 /* Copy the to the process and truncate it to 15 characters if necessary */
456 DPRINT("Copying and truncating\n");
457 szDest = Process->ImageFileName;
458 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
459 while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
460
461 /* Return status to caller */
462 return Status;
463 }
464
465 exit:
466 /* Unlock the Address Space */
467 DPRINT("Unlocking\n");
468 MmUnlockAddressSpace(ProcessAddressSpace);
469
470 /* Return status to caller */
471 return Status;
472 }