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