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)
9 /* INCLUDES ******************************************************************/
15 extern ULONG ExpInitializationPhase
;
17 PVOID KeUserPopEntrySListEnd
;
18 PVOID KeUserPopEntrySListFault
;
19 PVOID KeUserPopEntrySListResume
;
21 GENERIC_MAPPING PspProcessMapping
=
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
,
32 GENERIC_MAPPING PspThreadMapping
=
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
,
41 PVOID PspSystemDllBase
;
42 PVOID PspSystemDllSection
;
43 PVOID PspSystemDllEntryPoint
;
45 UNICODE_STRING PsNtDllPathName
=
46 RTL_CONSTANT_STRING(L
"\\SystemRoot\\System32\\ntdll.dll");
48 PHANDLE_TABLE PspCidTable
;
50 PEPROCESS PsInitialSystemProcess
= NULL
;
51 PEPROCESS PsIdleProcess
= NULL
;
52 HANDLE PspInitialSystemProcessHandle
= NULL
;
54 ULONG PsMinimumWorkingSet
, PsMaximumWorkingSet
;
59 } PspWorkingSetChangeHead
;
60 ULONG PspDefaultPagedLimit
, PspDefaultNonPagedLimit
, PspDefaultPagefileLimit
;
61 BOOLEAN PspDoingGiveBacks
;
63 /* PRIVATE FUNCTIONS *********************************************************/
68 NameToOrdinal(IN PCHAR Name
,
70 IN ULONG NumberOfNames
,
72 IN PUSHORT OrdinalTable
)
77 /* Fail if no names */
78 if (!NumberOfNames
) return -1;
80 /* Do binary search */
81 Mid
= NumberOfNames
>> 1;
82 Ret
= strcmp(Name
, (PCHAR
)((ULONG_PTR
)DllBase
+ NameTable
[Mid
]));
84 /* Check if we found it */
85 if (!Ret
) return OrdinalTable
[Mid
];
87 /* We didn't. Check if we only had one name to check */
88 if (NumberOfNames
== 1) return -1;
90 /* Check if we should look up or down */
98 /* Look up, update tables */
99 NameTable
= &NameTable
[Mid
+ 1];
100 OrdinalTable
= &OrdinalTable
[Mid
+ 1];
101 NumberOfNames
-= (Mid
- 1);
104 /* Call us recursively */
105 return NameToOrdinal(Name
, DllBase
, NumberOfNames
, NameTable
, OrdinalTable
);
111 LookupEntryPoint(IN PVOID DllBase
,
113 OUT PVOID
*EntryPoint
)
116 PUSHORT OrdinalTable
;
117 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
123 /* Get the export directory */
124 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
126 IMAGE_DIRECTORY_ENTRY_EXPORT
,
129 /* Validate the name and copy it */
130 if (strlen(Name
) > sizeof(Buffer
) - 2) return STATUS_INVALID_PARAMETER
;
131 strcpy(Buffer
, Name
);
133 /* Setup name tables */
134 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
135 ExportDirectory
->AddressOfNames
);
136 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
137 ExportDirectory
->AddressOfNameOrdinals
);
139 /* Get the ordinal */
140 Ordinal
= NameToOrdinal(Buffer
,
142 ExportDirectory
->NumberOfNames
,
146 /* Make sure the ordinal is valid */
147 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
150 return STATUS_PROCEDURE_NOT_FOUND
;
153 /* Resolve the address and write it */
154 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
155 ExportDirectory
->AddressOfFunctions
);
156 *EntryPoint
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
157 return STATUS_SUCCESS
;
163 PspLookupSystemDllEntryPoint(IN PCHAR Name
,
164 IN PVOID
*EntryPoint
)
166 /* Call the LDR Routine */
167 return LookupEntryPoint(PspSystemDllBase
, Name
, EntryPoint
);
173 PspLookupKernelUserEntryPoints(VOID
)
177 /* Get user-mode APC trampoline */
178 Status
= PspLookupSystemDllEntryPoint("KiUserApcDispatcher",
179 &KeUserApcDispatcher
);
180 if (!NT_SUCCESS(Status
)) return Status
;
182 /* Get user-mode exception dispatcher */
183 Status
= PspLookupSystemDllEntryPoint("KiUserExceptionDispatcher",
184 &KeUserExceptionDispatcher
);
185 if (!NT_SUCCESS(Status
)) return Status
;
187 /* Get user-mode callback dispatcher */
188 Status
= PspLookupSystemDllEntryPoint("KiUserCallbackDispatcher",
189 &KeUserCallbackDispatcher
);
190 if (!NT_SUCCESS(Status
)) return Status
;
192 /* Get user-mode exception raise trampoline */
193 Status
= PspLookupSystemDllEntryPoint("KiRaiseUserExceptionDispatcher",
194 &KeRaiseUserExceptionDispatcher
);
195 if (!NT_SUCCESS(Status
)) return Status
;
197 /* Get user-mode SLIST exception functions for page fault rollback race hack */
198 Status
= PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListEnd",
199 &KeUserPopEntrySListEnd
);
200 if (!NT_SUCCESS(Status
)) { DPRINT1("this not found\n"); return Status
; }
201 Status
= PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListFault",
202 &KeUserPopEntrySListFault
);
203 if (!NT_SUCCESS(Status
)) { DPRINT1("this not found\n"); return Status
; }
204 Status
= PspLookupSystemDllEntryPoint("ExpInterlockedPopEntrySListResume",
205 &KeUserPopEntrySListResume
);
206 if (!NT_SUCCESS(Status
)) { DPRINT1("this not found\n"); return Status
; }
208 /* On x86, there are multiple ways to do a system call, find the right stubs */
210 /* Check if this is a machine that supports SYSENTER */
211 if (KeFeatureBits
& KF_FAST_SYSCALL
)
213 /* Get user-mode sysenter stub */
214 SharedUserData
->SystemCall
= (PsNtosImageBase
>> (PAGE_SHIFT
+ 1));
215 Status
= PspLookupSystemDllEntryPoint("KiFastSystemCall",
216 (PVOID
)&SharedUserData
->
218 if (!NT_SUCCESS(Status
)) return Status
;
220 /* Get user-mode sysenter return stub */
221 Status
= PspLookupSystemDllEntryPoint("KiFastSystemCallRet",
222 (PVOID
)&SharedUserData
->
224 if (!NT_SUCCESS(Status
)) return Status
;
228 /* Get the user-mode interrupt stub */
229 Status
= PspLookupSystemDllEntryPoint("KiIntSystemCall",
230 (PVOID
)&SharedUserData
->
232 if (!NT_SUCCESS(Status
)) return Status
;
235 /* Set the test instruction */
236 SharedUserData
->TestRetInstruction
= 0xC3;
239 /* Return the status */
245 PspMapSystemDll(IN PEPROCESS Process
,
247 IN BOOLEAN UseLargePages
)
250 LARGE_INTEGER Offset
= {{0, 0}};
254 /* Map the System DLL */
255 Status
= MmMapViewOfSection(PspSystemDllSection
,
265 if (Status
!= STATUS_SUCCESS
)
267 /* Normalize status code */
268 Status
= STATUS_CONFLICTING_ADDRESSES
;
271 /* Write the image base and return status */
272 if (DllBase
) *DllBase
= ImageBase
;
279 PsLocateSystemDll(VOID
)
281 OBJECT_ATTRIBUTES ObjectAttributes
;
282 IO_STATUS_BLOCK IoStatusBlock
;
283 HANDLE FileHandle
, SectionHandle
;
285 ULONG_PTR HardErrorParameters
;
286 ULONG HardErrorResponse
;
288 /* Locate and open NTDLL to determine ImageBase and LdrStartup */
289 InitializeObjectAttributes(&ObjectAttributes
,
294 Status
= ZwOpenFile(&FileHandle
,
300 if (!NT_SUCCESS(Status
))
302 /* Failed, bugcheck */
303 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 2, 0, 0);
306 /* Check if the image is valid */
307 Status
= MmCheckSystemImage(FileHandle
, TRUE
);
308 if (Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
)
310 /* Raise a hard error */
311 HardErrorParameters
= (ULONG_PTR
)&PsNtDllPathName
;
312 NtRaiseHardError(Status
,
315 &HardErrorParameters
,
321 /* Create a section for NTDLL */
322 Status
= ZwCreateSection(&SectionHandle
,
330 if (!NT_SUCCESS(Status
))
332 /* Failed, bugcheck */
333 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 3, 0, 0);
336 /* Reference the Section */
337 Status
= ObReferenceObjectByHandle(SectionHandle
,
341 (PVOID
*)&PspSystemDllSection
,
343 ZwClose(SectionHandle
);
344 if (!NT_SUCCESS(Status
))
346 /* Failed, bugcheck */
347 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 4, 0, 0);
351 Status
= PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase
, FALSE
);
352 if (!NT_SUCCESS(Status
))
354 /* Failed, bugcheck */
355 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 5, 0, 0);
365 PspInitializeSystemDll(VOID
)
369 /* Get user-mode startup thunk */
370 Status
= PspLookupSystemDllEntryPoint("LdrInitializeThunk",
371 &PspSystemDllEntryPoint
);
372 if (!NT_SUCCESS(Status
))
374 /* Failed, bugcheck */
375 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 7, 0, 0);
378 /* Get all the other entrypoints */
379 Status
= PspLookupKernelUserEntryPoints();
380 if (!NT_SUCCESS(Status
))
382 /* Failed, bugcheck */
383 KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED
, Status
, 8, 0, 0);
387 /* Let KD know we are done */
400 /* Initialize the System DLL and return status of operation */
401 if (!NT_SUCCESS(PspInitializeSystemDll())) return FALSE
;
408 PspInitPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
411 OBJECT_ATTRIBUTES ObjectAttributes
;
412 HANDLE SysThreadHandle
;
414 MM_SYSTEMSIZE SystemSize
;
416 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
419 /* Get the system size */
420 SystemSize
= MmQuerySystemSize();
422 /* Setup some memory options */
423 PspDefaultPagefileLimit
= -1;
426 /* Medimum systems */
429 /* Increase the WS sizes a bit */
430 PsMinimumWorkingSet
+= 10;
431 PsMaximumWorkingSet
+= 100;
436 /* Increase the WS sizes a bit more */
437 PsMinimumWorkingSet
+= 30;
438 PsMaximumWorkingSet
+= 300;
440 /* Small and other systems */
445 /* Setup callbacks */
446 for (i
= 0; i
< PSP_MAX_CREATE_THREAD_NOTIFY
; i
++)
448 ExInitializeCallBack(&PspThreadNotifyRoutine
[i
]);
450 for (i
= 0; i
< PSP_MAX_CREATE_PROCESS_NOTIFY
; i
++)
452 ExInitializeCallBack(&PspProcessNotifyRoutine
[i
]);
454 for (i
= 0; i
< PSP_MAX_LOAD_IMAGE_NOTIFY
; i
++)
456 ExInitializeCallBack(&PspLoadImageNotifyRoutine
[i
]);
459 /* Setup the quantum table */
460 PsChangeQuantumTable(FALSE
, PsRawPrioritySeparation
);
462 /* Set quota settings */
463 if (!PspDefaultPagedLimit
) PspDefaultPagedLimit
= 0;
464 if (!PspDefaultNonPagedLimit
) PspDefaultNonPagedLimit
= 0;
465 if (!(PspDefaultNonPagedLimit
) && !(PspDefaultPagedLimit
))
467 /* Enable give-backs */
468 PspDoingGiveBacks
= TRUE
;
473 PspDoingGiveBacks
= FALSE
;
476 /* Now multiply limits by 1MB */
477 PspDefaultPagedLimit
<<= 20;
478 PspDefaultNonPagedLimit
<<= 20;
479 if (PspDefaultPagefileLimit
!= MAXULONG
) PspDefaultPagefileLimit
<<= 20;
481 /* Initialize the Active Process List */
482 InitializeListHead(&PsActiveProcessHead
);
483 KeInitializeGuardedMutex(&PspActiveProcessMutex
);
485 /* Get the idle process */
486 PsIdleProcess
= PsGetCurrentProcess();
488 /* Setup the locks */
489 PsIdleProcess
->ProcessLock
.Value
= 0;
490 ExInitializeRundownProtection(&PsIdleProcess
->RundownProtect
);
492 /* Initialize the thread list */
493 InitializeListHead(&PsIdleProcess
->ThreadListHead
);
495 /* Clear kernel time */
496 PsIdleProcess
->Pcb
.KernelTime
= 0;
498 /* Initialize Object Initializer */
499 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
500 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
501 ObjectTypeInitializer
.InvalidAttributes
= OBJ_PERMANENT
|
504 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
505 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
507 /* Initialize the Process type */
508 RtlInitUnicodeString(&Name
, L
"Process");
509 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(EPROCESS
);
510 ObjectTypeInitializer
.GenericMapping
= PspProcessMapping
;
511 ObjectTypeInitializer
.ValidAccessMask
= PROCESS_ALL_ACCESS
;
512 ObjectTypeInitializer
.DeleteProcedure
= PspDeleteProcess
;
513 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &PsProcessType
);
515 /* Initialize the Thread type */
516 RtlInitUnicodeString(&Name
, L
"Thread");
517 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
518 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(ETHREAD
);
519 ObjectTypeInitializer
.GenericMapping
= PspThreadMapping
;
520 ObjectTypeInitializer
.ValidAccessMask
= THREAD_ALL_ACCESS
;
521 ObjectTypeInitializer
.DeleteProcedure
= PspDeleteThread
;
522 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &PsThreadType
);
524 /* Initialize the Job type */
525 RtlInitUnicodeString(&Name
, L
"Job");
526 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
527 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(EJOB
);
528 ObjectTypeInitializer
.GenericMapping
= PspJobMapping
;
529 ObjectTypeInitializer
.InvalidAttributes
= 0;
530 ObjectTypeInitializer
.ValidAccessMask
= JOB_OBJECT_ALL_ACCESS
;
531 ObjectTypeInitializer
.DeleteProcedure
= PspDeleteJob
;
532 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &PsJobType
);
534 /* Initialize job structures external to this file */
535 PspInitializeJobStructures();
537 /* Initialize the Working Set data */
538 InitializeListHead(&PspWorkingSetChangeHead
.List
);
539 KeInitializeGuardedMutex(&PspWorkingSetChangeHead
.Lock
);
541 /* Create the CID Handle table */
542 PspCidTable
= ExCreateHandleTable(NULL
);
543 if (!PspCidTable
) return FALSE
;
545 /* FIXME: Initialize LDT/VDM support */
547 /* Setup the reaper */
548 ExInitializeWorkItem(&PspReaperWorkItem
, PspReapRoutine
, NULL
);
550 /* Set the boot access token */
551 PspBootAccessToken
= (PTOKEN
)(PsIdleProcess
->Token
.Value
& ~MAX_FAST_REFS
);
553 /* Setup default object attributes */
554 InitializeObjectAttributes(&ObjectAttributes
,
560 /* Create the Initial System Process */
561 Status
= PspCreateProcess(&PspInitialSystemProcessHandle
,
570 if (!NT_SUCCESS(Status
)) return FALSE
;
572 /* Get a reference to it */
573 ObReferenceObjectByHandle(PspInitialSystemProcessHandle
,
577 (PVOID
*)&PsInitialSystemProcess
,
580 /* Copy the process names */
581 strcpy(PsIdleProcess
->ImageFileName
, "Idle");
582 strcpy(PsInitialSystemProcess
->ImageFileName
, "System");
584 /* Allocate a structure for the audit name */
585 PsInitialSystemProcess
->SeAuditProcessCreationInfo
.ImageFileName
=
586 ExAllocatePoolWithTag(PagedPool
,
587 sizeof(OBJECT_NAME_INFORMATION
),
589 if (!PsInitialSystemProcess
->SeAuditProcessCreationInfo
.ImageFileName
)
591 /* Allocation failed */
596 RtlZeroMemory(PsInitialSystemProcess
->
597 SeAuditProcessCreationInfo
.ImageFileName
,
598 sizeof(OBJECT_NAME_INFORMATION
));
600 /* Setup the system initialization thread */
601 Status
= PsCreateSystemThread(&SysThreadHandle
,
606 Phase1Initialization
,
608 if (!NT_SUCCESS(Status
)) return FALSE
;
610 /* Create a handle to it */
611 ObReferenceObjectByHandle(SysThreadHandle
,
617 ObCloseHandle(SysThreadHandle
, KernelMode
);
626 PsInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
628 /* Check the initialization phase */
629 switch (ExpInitializationPhase
)
634 return PspInitPhase0(LoaderBlock
);
639 return PspInitPhase1();
643 /* Don't know any other phase! Bugcheck! */
644 KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL
,
646 ExpInitializationPhase
,
653 /* PUBLIC FUNCTIONS **********************************************************/
660 PsGetVersion(OUT PULONG MajorVersion OPTIONAL
,
661 OUT PULONG MinorVersion OPTIONAL
,
662 OUT PULONG BuildNumber OPTIONAL
,
663 OUT PUNICODE_STRING CSDVersion OPTIONAL
)
665 if (MajorVersion
) *MajorVersion
= NtMajorVersion
;
666 if (MinorVersion
) *MinorVersion
= NtMinorVersion
;
667 if (BuildNumber
) *BuildNumber
= NtBuildNumber
& 0x3FFF;
671 CSDVersion
->Length
= CmCSDVersionString
.Length
;
672 CSDVersion
->MaximumLength
= CmCSDVersionString
.MaximumLength
;
673 CSDVersion
->Buffer
= CmCSDVersionString
.Buffer
;
676 /* Return TRUE if this is a Checked Build */
677 return (NtBuildNumber
>> 28) == 0xC;
682 NtApphelpCacheControl(IN APPHELPCACHESERVICECLASS Service
,
683 IN PVOID ServiceData
)
686 return STATUS_NOT_IMPLEMENTED
;