1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/psmgr.c
5 * PURPOSE: Process Manager: Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 extern ULONG ExpInitializationPhase;
16
17 PVOID KeUserPopEntrySListEnd;
18 PVOID KeUserPopEntrySListFault;
19 PVOID KeUserPopEntrySListResume;
20
21 GENERIC_MAPPING PspProcessMapping =
22 {
23 STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
24 STANDARD_RIGHTS_WRITE | PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
25 PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE |
26 PROCESS_TERMINATE | PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
27 PROCESS_SUSPEND_RESUME,
28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
29 PROCESS_ALL_ACCESS
30 };
31
32 GENERIC_MAPPING PspThreadMapping =
33 {
34 STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
35 STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME |
36 THREAD_ALERT | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT,
37 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
38 THREAD_ALL_ACCESS
39 };
40
41 PVOID PspSystemDllBase;
42 PVOID PspSystemDllSection;
43 PVOID PspSystemDllEntryPoint;
44
45 UNICODE_STRING PsNtDllPathName =
46 RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\ntdll.dll");
47
48 PHANDLE_TABLE PspCidTable;
49
50 PEPROCESS PsInitialSystemProcess = NULL;
51 PEPROCESS PsIdleProcess = NULL;
52 HANDLE PspInitialSystemProcessHandle = NULL;
53
54 ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
55 struct
56 {
57 LIST_ENTRY List;
58 KGUARDED_MUTEX Lock;
59 } PspWorkingSetChangeHead;
60 ULONG PspDefaultPagedLimit, PspDefaultNonPagedLimit, PspDefaultPagefileLimit;
61 BOOLEAN PspDoingGiveBacks;
62
63 /* PRIVATE FUNCTIONS *********************************************************/
64
65 static CODE_SEG("INIT")
66 NTSTATUS
PspLookupSystemDllEntryPoint(_In_ PCSTR Name,_Out_ PVOID * EntryPoint)67 PspLookupSystemDllEntryPoint(
68 _In_ PCSTR Name,
69 _Out_ PVOID* EntryPoint)
70 {
71 /* Call the internal API */
72 return RtlpFindExportedRoutineByName(PspSystemDllBase,
73 Name,
74 EntryPoint,
75 NULL,
76 STATUS_PROCEDURE_NOT_FOUND);
77 }
78
79 static CODE_SEG("INIT")
80 NTSTATUS
PspLookupKernelUserEntryPoints(VOID)81 PspLookupKernelUserEntryPoints(VOID)
82 {
83 NTSTATUS Status;
84
85 /* Get user-mode APC trampoline */
86 Status = PspLookupSystemDllEntryPoint("KiUserApcDispatcher",
87 &KeUserApcDispatcher);
88 if (!NT_SUCCESS(Status)) return Status;
89
90 /* Get user-mode exception dispatcher */
91 Status = PspLookupSystemDllEntryPoint("KiUserExceptionDispatcher",
92 &KeUserExceptionDispatcher);
93 if (!NT_SUCCESS(Status)) return Status;
94
95 /* Get user-mode callback dispatcher */
96 Status = PspLookupSystemDllEntryPoint("KiUserCallbackDispatcher",
97 &KeUserCallbackDispatcher);
98 if (!NT_SUCCESS(Status)) return Status;
99
100 /* Get user-mode exception raise trampoline */
101 Status = PspLookupSystemDllEntryPoint("KiRaiseUserExceptionDispatcher",
102 &KeRaiseUserExceptionDispatcher);
103 if (!NT_SUCCESS(Status)) return Status;
104
105 /* Get user-mode SLIST exception functions for page fault rollback race hack */
106 Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListEnd",
107 &KeUserPopEntrySListEnd);
108 if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
109 Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListFault",
110 &KeUserPopEntrySListFault);
111 if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
112 Status = PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListResume",
113 &KeUserPopEntrySListResume);
114 if (!NT_SUCCESS(Status)) { DPRINT1("this not found\n"); return Status; }
115
116 /* On x86, there are multiple ways to do a system call, find the right stubs */
117 #if defined(_X86_)
118 /* Check if this is a machine that supports SYSENTER */
119 if (KeFeatureBits & KF_FAST_SYSCALL)
120 {
121 /* Get user-mode sysenter stub */
122 SharedUserData->SystemCall = (PsNtosImageBase >> (PAGE_SHIFT + 1));
123 Status = PspLookupSystemDllEntryPoint("KiFastSystemCall",
124 (PVOID)&SharedUserData->
125 SystemCall);
126 if (!NT_SUCCESS(Status)) return Status;
127
128 /* Get user-mode sysenter return stub */
129 Status = PspLookupSystemDllEntryPoint("KiFastSystemCallRet",
130 (PVOID)&SharedUserData->
131 SystemCallReturn);
132 if (!NT_SUCCESS(Status)) return Status;
133 }
134 else
135 {
136 /* Get the user-mode interrupt stub */
137 Status = PspLookupSystemDllEntryPoint("KiIntSystemCall",
138 (PVOID)&SharedUserData->
139 SystemCall);
140 if (!NT_SUCCESS(Status)) return Status;
141 }
142
143 /* Set the test instruction */
144 SharedUserData->TestRetInstruction = 0xC3;
145 #endif
146
147 /* Return the status */
148 return Status;
149 }
150
151 NTSTATUS
152 NTAPI
PspMapSystemDll(IN PEPROCESS Process,IN PVOID * DllBase,IN BOOLEAN UseLargePages)153 PspMapSystemDll(IN PEPROCESS Process,
154 IN PVOID *DllBase,
155 IN BOOLEAN UseLargePages)
156 {
157 NTSTATUS Status;
158 LARGE_INTEGER Offset = {{0, 0}};
159 SIZE_T ViewSize = 0;
160 PVOID ImageBase = 0;
161
162 /* Map the System DLL */
163 Status = MmMapViewOfSection(PspSystemDllSection,
164 Process,
165 (PVOID*)&ImageBase,
166 0,
167 0,
168 &Offset,
169 &ViewSize,
170 ViewShare,
171 0,
172 PAGE_READWRITE);
173 if (Status != STATUS_SUCCESS)
174 {
175 /* Normalize status code */
176 Status = STATUS_CONFLICTING_ADDRESSES;
177 }
178
179 /* Write the image base and return status */
180 if (DllBase) *DllBase = ImageBase;
181 return Status;
182 }
183
184 CODE_SEG("INIT")
185 NTSTATUS
186 NTAPI
PsLocateSystemDll(VOID)187 PsLocateSystemDll(VOID)
188 {
189 OBJECT_ATTRIBUTES ObjectAttributes;
190 IO_STATUS_BLOCK IoStatusBlock;
191 HANDLE FileHandle, SectionHandle;
192 NTSTATUS Status;
193 ULONG_PTR HardErrorParameters;
194 ULONG HardErrorResponse;
195
196 /* Locate and open NTDLL to determine ImageBase and LdrStartup */
197 InitializeObjectAttributes(&ObjectAttributes,
198 &PsNtDllPathName,
199 0,
200 NULL,
201 NULL);
202 Status = ZwOpenFile(&FileHandle,
203 FILE_READ_ACCESS,
204 &ObjectAttributes,
205 &IoStatusBlock,
206 FILE_SHARE_READ,
207 0);
208 if (!NT_SUCCESS(Status))
209 {
210 /* Failed, bugcheck */
211 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 2, 0, 0);
212 }
213
214 /* Check if the image is valid */
215 Status = MmCheckSystemImage(FileHandle, TRUE);
216 if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH)
217 {
218 /* Raise a hard error */
219 HardErrorParameters = (ULONG_PTR)&PsNtDllPathName;
220 NtRaiseHardError(Status,
221 1,
222 1,
223 &HardErrorParameters,
224 OptionOk,
225 &HardErrorResponse);
226 return Status;
227 }
228
229 /* Create a section for NTDLL */
230 Status = ZwCreateSection(&SectionHandle,
231 SECTION_ALL_ACCESS,
232 NULL,
233 NULL,
234 PAGE_EXECUTE,
235 SEC_IMAGE,
236 FileHandle);
237 ZwClose(FileHandle);
238 if (!NT_SUCCESS(Status))
239 {
240 /* Failed, bugcheck */
241 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 3, 0, 0);
242 }
243
244 /* Reference the Section */
245 Status = ObReferenceObjectByHandle(SectionHandle,
246 SECTION_ALL_ACCESS,
247 MmSectionObjectType,
248 KernelMode,
249 (PVOID*)&PspSystemDllSection,
250 NULL);
251 ZwClose(SectionHandle);
252 if (!NT_SUCCESS(Status))
253 {
254 /* Failed, bugcheck */
255 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 4, 0, 0);
256 }
257
258 /* Map it */
259 Status = PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase, FALSE);
260 if (!NT_SUCCESS(Status))
261 {
262 /* Failed, bugcheck */
263 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 5, 0, 0);
264 }
265
266 /* Return status */
267 return Status;
268 }
269
270 CODE_SEG("INIT")
271 NTSTATUS
272 NTAPI
PspInitializeSystemDll(VOID)273 PspInitializeSystemDll(VOID)
274 {
275 NTSTATUS Status;
276
277 /* Get user-mode startup thunk */
278 Status = PspLookupSystemDllEntryPoint("LdrInitializeThunk",
279 &PspSystemDllEntryPoint);
280 if (!NT_SUCCESS(Status))
281 {
282 /* Failed, bugcheck */
283 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 7, 0, 0);
284 }
285
286 /* Get all the other entrypoints */
287 Status = PspLookupKernelUserEntryPoints();
288 if (!NT_SUCCESS(Status))
289 {
290 /* Failed, bugcheck */
291 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 8, 0, 0);
292 }
293
294 /* Let KD know we are done */
295 KdUpdateDataBlock();
296
297 /* Return status */
298 return Status;
299 }
300
301 CODE_SEG("INIT")
302 BOOLEAN
303 NTAPI
PspInitPhase1(VOID)304 PspInitPhase1(VOID)
305 {
306 /* Initialize the System DLL and return status of operation */
307 if (!NT_SUCCESS(PspInitializeSystemDll())) return FALSE;
308 return TRUE;
309 }
310
311 CODE_SEG("INIT")
312 BOOLEAN
313 NTAPI
PspInitPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)314 PspInitPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
315 {
316 NTSTATUS Status;
317 OBJECT_ATTRIBUTES ObjectAttributes;
318 HANDLE SysThreadHandle;
319 PETHREAD SysThread;
320 MM_SYSTEMSIZE SystemSize;
321 UNICODE_STRING Name;
322 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
323 ULONG i;
324
325 /* Get the system size */
326 SystemSize = MmQuerySystemSize();
327
328 /* Setup some memory options */
329 PspDefaultPagefileLimit = -1;
330 switch (SystemSize)
331 {
332 /* Medimum systems */
333 case MmMediumSystem:
334
335 /* Increase the WS sizes a bit */
336 PsMinimumWorkingSet += 10;
337 PsMaximumWorkingSet += 100;
338
339 /* Large systems */
340 case MmLargeSystem:
341
342 /* Increase the WS sizes a bit more */
343 PsMinimumWorkingSet += 30;
344 PsMaximumWorkingSet += 300;
345
346 /* Small and other systems */
347 default:
348 break;
349 }
350
351 /* Setup callbacks */
352 for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
353 {
354 ExInitializeCallBack(&PspThreadNotifyRoutine[i]);
355 }
356 for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
357 {
358 ExInitializeCallBack(&PspProcessNotifyRoutine[i]);
359 }
360 for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
361 {
362 ExInitializeCallBack(&PspLoadImageNotifyRoutine[i]);
363 }
364
365 /* Setup the quantum table */
366 PsChangeQuantumTable(FALSE, PsRawPrioritySeparation);
367
368 /* Set quota settings */
369 if (!PspDefaultPagedLimit) PspDefaultPagedLimit = 0;
370 if (!PspDefaultNonPagedLimit) PspDefaultNonPagedLimit = 0;
371 if (!(PspDefaultNonPagedLimit) && !(PspDefaultPagedLimit))
372 {
373 /* Enable give-backs */
374 PspDoingGiveBacks = TRUE;
375 }
376 else
377 {
378 /* Disable them */
379 PspDoingGiveBacks = FALSE;
380 }
381
382 /* Now multiply limits by 1MB */
383 PspDefaultPagedLimit <<= 20;
384 PspDefaultNonPagedLimit <<= 20;
385 if (PspDefaultPagefileLimit != MAXULONG) PspDefaultPagefileLimit <<= 20;
386
387 /* Initialize the Active Process List */
388 InitializeListHead(&PsActiveProcessHead);
389 KeInitializeGuardedMutex(&PspActiveProcessMutex);
390
391 /* Get the idle process */
392 PsIdleProcess = PsGetCurrentProcess();
393
394 /* Setup the locks */
395 PsIdleProcess->ProcessLock.Value = 0;
396 ExInitializeRundownProtection(&PsIdleProcess->RundownProtect);
397
398 /* Initialize the thread list */
399 InitializeListHead(&PsIdleProcess->ThreadListHead);
400
401 /* Clear kernel time */
402 PsIdleProcess->Pcb.KernelTime = 0;
403
404 /* Initialize Object Initializer */
405 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
406 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
407 ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT |
408 OBJ_EXCLUSIVE |
409 OBJ_OPENIF;
410 ObjectTypeInitializer.PoolType = NonPagedPool;
411 ObjectTypeInitializer.SecurityRequired = TRUE;
412
413 /* Initialize the Process type */
414 RtlInitUnicodeString(&Name, L"Process");
415 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPROCESS);
416 ObjectTypeInitializer.GenericMapping = PspProcessMapping;
417 ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
418 ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
419 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsProcessType);
420
421 /* Initialize the Thread type */
422 RtlInitUnicodeString(&Name, L"Thread");
423 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
424 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETHREAD);
425 ObjectTypeInitializer.GenericMapping = PspThreadMapping;
426 ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
427 ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
428 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsThreadType);
429
430 /* Initialize the Job type */
431 RtlInitUnicodeString(&Name, L"Job");
432 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
433 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EJOB);
434 ObjectTypeInitializer.GenericMapping = PspJobMapping;
435 ObjectTypeInitializer.InvalidAttributes = 0;
436 ObjectTypeInitializer.ValidAccessMask = JOB_OBJECT_ALL_ACCESS;
437 ObjectTypeInitializer.DeleteProcedure = PspDeleteJob;
438 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &PsJobType);
439
440 /* Initialize job structures external to this file */
441 PspInitializeJobStructures();
442
443 /* Initialize the Working Set data */
444 InitializeListHead(&PspWorkingSetChangeHead.List);
445 KeInitializeGuardedMutex(&PspWorkingSetChangeHead.Lock);
446
447 /* Create the CID Handle table */
448 PspCidTable = ExCreateHandleTable(NULL);
449 if (!PspCidTable) return FALSE;
450
451 /* FIXME: Initialize LDT/VDM support */
452
453 /* Setup the reaper */
454 ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL);
455
456 /* Set the boot access token */
457 PspBootAccessToken = (PTOKEN)(PsIdleProcess->Token.Value & ~MAX_FAST_REFS);
458
459 /* Setup default object attributes */
460 InitializeObjectAttributes(&ObjectAttributes,
461 NULL,
462 0,
463 NULL,
464 NULL);
465
466 /* Create the Initial System Process */
467 Status = PspCreateProcess(&PspInitialSystemProcessHandle,
468 PROCESS_ALL_ACCESS,
469 &ObjectAttributes,
470 0,
471 FALSE,
472 0,
473 0,
474 0,
475 FALSE);
476 if (!NT_SUCCESS(Status)) return FALSE;
477
478 /* Get a reference to it */
479 ObReferenceObjectByHandle(PspInitialSystemProcessHandle,
480 0,
481 PsProcessType,
482 KernelMode,
483 (PVOID*)&PsInitialSystemProcess,
484 NULL);
485
486 /* Copy the process names */
487 strcpy(PsIdleProcess->ImageFileName, "Idle");
488 strcpy(PsInitialSystemProcess->ImageFileName, "System");
489
490 /* Allocate a structure for the audit name */
491 PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName =
492 ExAllocatePoolWithTag(PagedPool,
493 sizeof(OBJECT_NAME_INFORMATION),
494 TAG_SEPA);
495 if (!PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName)
496 {
497 /* Allocation failed */
498 return FALSE;
499 }
500
501 /* Zero it */
502 RtlZeroMemory(PsInitialSystemProcess->
503 SeAuditProcessCreationInfo.ImageFileName,
504 sizeof(OBJECT_NAME_INFORMATION));
505
506 /* Setup the system initialization thread */
507 Status = PsCreateSystemThread(&SysThreadHandle,
508 THREAD_ALL_ACCESS,
509 &ObjectAttributes,
510 0,
511 NULL,
512 Phase1Initialization,
513 LoaderBlock);
514 if (!NT_SUCCESS(Status)) return FALSE;
515
516 /* Create a handle to it */
517 ObReferenceObjectByHandle(SysThreadHandle,
518 0,
519 PsThreadType,
520 KernelMode,
521 (PVOID*)&SysThread,
522 NULL);
523 ObCloseHandle(SysThreadHandle, KernelMode);
524
525 /* Return success */
526 return TRUE;
527 }
528
529 CODE_SEG("INIT")
530 BOOLEAN
531 NTAPI
PsInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)532 PsInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
533 {
534 /* Check the initialization phase */
535 switch (ExpInitializationPhase)
536 {
537 case 0:
538
539 /* Do Phase 0 */
540 return PspInitPhase0(LoaderBlock);
541
542 case 1:
543
544 /* Do Phase 1 */
545 return PspInitPhase1();
546
547 default:
548
549 /* Don't know any other phase! Bugcheck! */
550 KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL,
551 1,
552 ExpInitializationPhase,
553 0,
554 0);
555 return FALSE;
556 }
557 }
558
559 /* PUBLIC FUNCTIONS **********************************************************/
560
561 /*
562 * @implemented
563 */
564 BOOLEAN
565 NTAPI
PsGetVersion(OUT PULONG MajorVersion OPTIONAL,OUT PULONG MinorVersion OPTIONAL,OUT PULONG BuildNumber OPTIONAL,OUT PUNICODE_STRING CSDVersion OPTIONAL)566 PsGetVersion(OUT PULONG MajorVersion OPTIONAL,
567 OUT PULONG MinorVersion OPTIONAL,
568 OUT PULONG BuildNumber OPTIONAL,
569 OUT PUNICODE_STRING CSDVersion OPTIONAL)
570 {
571 if (MajorVersion) *MajorVersion = NtMajorVersion;
572 if (MinorVersion) *MinorVersion = NtMinorVersion;
573 if (BuildNumber ) *BuildNumber = NtBuildNumber & 0x3FFF;
574
575 if (CSDVersion)
576 {
577 CSDVersion->Length = CmCSDVersionString.Length;
578 CSDVersion->MaximumLength = CmCSDVersionString.MaximumLength;
579 CSDVersion->Buffer = CmCSDVersionString.Buffer;
580 }
581
582 /* Return TRUE if this is a Checked Build */
583 return (NtBuildNumber >> 28) == 0xC;
584 }
585
586 /* EOF */
587