xref: /reactos/ntoskrnl/ps/psmgr.c (revision cce399e7)
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
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
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
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
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
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
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
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
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
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