Implement PsSetLegoNotifyRoutine and PsRemoveCreateThreadNotifyroutine. Clean up...
[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 BoundaryAddressMultiple.QuadPart = 0;
32 PVOID AllocatedBase = BaseAddress;
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 = 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 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->Peb = Process->Peb;
311 Teb->CurrentLocale = PsDefaultThreadLocaleId;
312
313 /* Store stack information from InitialTeb */
314 if(InitialTeb != NULL)
315 {
316 /* fixed-size stack */
317 if(InitialTeb->StackBase && InitialTeb->StackLimit)
318 {
319 Teb->Tib.StackBase = InitialTeb->StackBase;
320 Teb->Tib.StackLimit = InitialTeb->StackLimit;
321 Teb->DeallocationStack = InitialTeb->StackLimit;
322 }
323 /* expandable stack */
324 else
325 {
326 Teb->Tib.StackBase = InitialTeb->StackCommit;
327 Teb->Tib.StackLimit = InitialTeb->StackCommitMax;
328 Teb->DeallocationStack = InitialTeb->StackReserved;
329 }
330 }
331
332 /* Return TEB Address */
333 DPRINT("Allocated: %x\n", Teb);
334 if (Attached) KeDetachProcess();
335 return Teb;
336 }
337
338 NTSTATUS
339 STDCALL
340 MmCreateProcessAddressSpace(IN PEPROCESS Process,
341 IN PSECTION_OBJECT Section OPTIONAL)
342 {
343 NTSTATUS Status;
344 PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
345 PVOID BaseAddress;
346 PMEMORY_AREA MemoryArea;
347 PHYSICAL_ADDRESS BoundaryAddressMultiple;
348 BoundaryAddressMultiple.QuadPart = 0;
349 ULONG ViewSize = 0;
350 PVOID ImageBase = 0;
351
352 /* Initialize the Addresss Space */
353 MmInitializeAddressSpace(Process, ProcessAddressSpace);
354
355 /* Acquire the Lock */
356 MmLockAddressSpace(ProcessAddressSpace);
357
358 /* Protect the highest 64KB of the process address space */
359 BaseAddress = (PVOID)MmUserProbeAddress;
360 Status = MmCreateMemoryArea(Process,
361 ProcessAddressSpace,
362 MEMORY_AREA_NO_ACCESS,
363 &BaseAddress,
364 0x10000,
365 PAGE_NOACCESS,
366 &MemoryArea,
367 FALSE,
368 FALSE,
369 BoundaryAddressMultiple);
370 if (!NT_SUCCESS(Status))
371 {
372 DPRINT1("Failed to protect last 64KB\n");
373 goto exit;
374 }
375
376 /* Protect the 60KB above the shared user page */
377 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
378 Status = MmCreateMemoryArea(Process,
379 ProcessAddressSpace,
380 MEMORY_AREA_NO_ACCESS,
381 &BaseAddress,
382 0x10000 - PAGE_SIZE,
383 PAGE_NOACCESS,
384 &MemoryArea,
385 FALSE,
386 FALSE,
387 BoundaryAddressMultiple);
388 if (!NT_SUCCESS(Status))
389 {
390 DPRINT1("Failed to protect the memory above the shared user page\n");
391 goto exit;
392 }
393
394 /* Create the shared data page */
395 BaseAddress = (PVOID)USER_SHARED_DATA;
396 Status = MmCreateMemoryArea(Process,
397 ProcessAddressSpace,
398 MEMORY_AREA_SHARED_DATA,
399 &BaseAddress,
400 PAGE_SIZE,
401 PAGE_READONLY,
402 &MemoryArea,
403 FALSE,
404 FALSE,
405 BoundaryAddressMultiple);
406 if (!NT_SUCCESS(Status))
407 {
408 DPRINT1("Failed to create Shared User Data\n");
409 goto exit;
410 }
411
412 /* Check if there's a Section Object */
413 if (Section)
414 {
415 UNICODE_STRING FileName;
416 PWCHAR szSrc;
417 PCHAR szDest;
418 USHORT lnFName = 0;
419
420 /* Unlock the Address Space */
421 DPRINT("Unlocking\n");
422 MmUnlockAddressSpace(ProcessAddressSpace);
423
424 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
425 Section, Process, &ImageBase);
426 Status = MmMapViewOfSection(Section,
427 Process,
428 (PVOID*)&ImageBase,
429 0,
430 0,
431 NULL,
432 &ViewSize,
433 0,
434 MEM_COMMIT,
435 PAGE_READWRITE);
436 if (!NT_SUCCESS(Status))
437 {
438 DPRINT1("Failed to map process Image\n");
439 ObDereferenceObject(Section);
440 goto exit;
441 }
442 ObDereferenceObject(Section);
443
444 /* Save the pointer */
445 Process->SectionBaseAddress = ImageBase;
446
447 /* Determine the image file name and save it to EPROCESS */
448 DPRINT("Getting Image name\n");
449 FileName = Section->FileObject->FileName;
450 szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
451
452 while(szSrc >= FileName.Buffer)
453 {
454 if(*szSrc == L'\\')
455 {
456 szSrc++;
457 break;
458 }
459 else
460 {
461 szSrc--;
462 lnFName++;
463 }
464 }
465
466 /* Copy the to the process and truncate it to 15 characters if necessary */
467 DPRINT("Copying and truncating\n");
468 szDest = Process->ImageFileName;
469 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
470 while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
471
472 /* Return status to caller */
473 return Status;
474 }
475
476 exit:
477 /* Unlock the Address Space */
478 DPRINT("Unlocking\n");
479 MmUnlockAddressSpace(ProcessAddressSpace);
480
481 /* Return status to caller */
482 return Status;
483 }