Allow the system process and a process without a parent process to use all cpus on...
[reactos.git] / reactos / ntoskrnl / ps / psmgr.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/psmgr.c
6 * PURPOSE: Process management
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES **************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 extern LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
18 extern LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
19
20 static GENERIC_MAPPING PiProcessMapping = {
21 STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
22 STANDARD_RIGHTS_WRITE | PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
23 PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE |
24 PROCESS_TERMINATE | PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
25 PROCESS_SUSPEND_RESUME,
26 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
27 PROCESS_ALL_ACCESS};
28
29 static GENERIC_MAPPING PiThreadMapping = {
30 STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
31 STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME |
32 THREAD_ALERT | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT,
33 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
34 THREAD_ALL_ACCESS};
35
36 extern ULONG NtBuildNumber;
37 extern ULONG NtMajorVersion;
38 extern ULONG NtMinorVersion;
39 extern PVOID KeUserApcDispatcher;
40 extern PVOID KeUserCallbackDispatcher;
41 extern PVOID KeUserExceptionDispatcher;
42 extern PVOID KeRaiseUserExceptionDispatcher;
43
44 PVOID PspSystemDllBase = NULL;
45 PVOID PspSystemDllSection = NULL;
46 PVOID PspSystemDllEntryPoint = NULL;
47 PHANDLE_TABLE PspCidTable = NULL;
48 VOID STDCALL PspKillMostProcesses();
49
50 /* FUNCTIONS ***************************************************************/
51
52 VOID
53 NTAPI
54 PiShutdownProcessManager(VOID)
55 {
56 DPRINT("PiShutdownProcessManager()\n");
57
58 PspKillMostProcesses();
59 }
60
61 VOID
62 INIT_FUNCTION
63 NTAPI
64 PiInitProcessManager(VOID)
65 {
66 PsInitJobManagment();
67 PsInitProcessManagment();
68 PsInitThreadManagment();
69 PsInitIdleThread();
70 PsInitialiseW32Call();
71 }
72
73 VOID
74 INIT_FUNCTION
75 NTAPI
76 PsInitClientIDManagment(VOID)
77 {
78 PspCidTable = ExCreateHandleTable(NULL);
79 ASSERT(PspCidTable);
80 }
81
82 VOID
83 INIT_FUNCTION
84 NTAPI
85 PsInitThreadManagment(VOID)
86 /*
87 * FUNCTION: Initialize thread managment
88 */
89 {
90 UNICODE_STRING Name;
91 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
92 PETHREAD FirstThread;
93 ULONG i;
94
95 for (i=0; i < MAXIMUM_PRIORITY; i++)
96 {
97 InitializeListHead(&PriorityListHead[i]);
98 }
99
100 DPRINT("Creating Thread Object Type\n");
101
102 /* Initialize the Thread type */
103 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
104 RtlInitUnicodeString(&Name, L"Thread");
105 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
106 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETHREAD);
107 ObjectTypeInitializer.GenericMapping = PiThreadMapping;
108 ObjectTypeInitializer.PoolType = NonPagedPool;
109 ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
110 ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
111 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsThreadType);
112
113 PsInitializeIdleOrFirstThread(PsInitialSystemProcess, &FirstThread, NULL, KernelMode, TRUE);
114 FirstThread->Tcb.State = Running;
115 FirstThread->Tcb.FreezeCount = 0;
116 FirstThread->Tcb.UserAffinity = (1 << 0); /* Set the affinity of the first thread to the boot processor */
117 FirstThread->Tcb.Affinity = (1 << 0);
118 KeGetCurrentPrcb()->CurrentThread = (PVOID)FirstThread;
119
120 DPRINT("FirstThread %x\n",FirstThread);
121
122 ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL);
123 }
124
125 VOID
126 INIT_FUNCTION
127 NTAPI
128 PsInitProcessManagment(VOID)
129 {
130 PKPROCESS KProcess;
131 NTSTATUS Status;
132 UNICODE_STRING Name;
133 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
134
135 ShortPsLockDelay.QuadPart = -100LL;
136 PsLockTimeout.QuadPart = -10000000LL; /* one second */
137 /*
138 * Register the process object type
139 */
140
141 DPRINT("Creating Process Object Type\n");
142
143 /* Initialize the Process type */
144 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
145 RtlInitUnicodeString(&Name, L"Process");
146 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
147 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPROCESS);
148 ObjectTypeInitializer.GenericMapping = PiProcessMapping;
149 ObjectTypeInitializer.PoolType = NonPagedPool;
150 ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
151 ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
152 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsProcessType);
153
154 InitializeListHead(&PsActiveProcessHead);
155 ExInitializeFastMutex(&PspActiveProcessMutex);
156
157 /*
158 * Initialize the default quota block.
159 */
160
161 RtlZeroMemory(&PspDefaultQuotaBlock, sizeof(PspDefaultQuotaBlock));
162 PspDefaultQuotaBlock.QuotaEntry[PagedPool].Limit = (SIZE_T)-1;
163 PspDefaultQuotaBlock.QuotaEntry[NonPagedPool].Limit = (SIZE_T)-1;
164 PspDefaultQuotaBlock.QuotaEntry[2].Limit = (SIZE_T)-1; /* Page file */
165
166 /*
167 * Initialize the idle process
168 */
169 Status = ObCreateObject(KernelMode,
170 PsProcessType,
171 NULL,
172 KernelMode,
173 NULL,
174 sizeof(EPROCESS),
175 0,
176 0,
177 (PVOID*)&PsIdleProcess);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("Failed to create the idle process object, Status: 0x%x\n", Status);
181 KEBUGCHECK(0);
182 return;
183 }
184
185 RtlZeroMemory(PsIdleProcess, sizeof(EPROCESS));
186
187 PsIdleProcess->Pcb.Affinity = 0xFFFFFFFF;
188 PsIdleProcess->Pcb.IopmOffset = 0xffff;
189 PsIdleProcess->Pcb.BasePriority = PROCESS_PRIORITY_IDLE;
190 PsIdleProcess->Pcb.QuantumReset = 6;
191 InitializeListHead(&PsIdleProcess->Pcb.ThreadListHead);
192 InitializeListHead(&PsIdleProcess->ThreadListHead);
193 InitializeListHead(&PsIdleProcess->ActiveProcessLinks);
194 KeInitializeDispatcherHeader(&PsIdleProcess->Pcb.Header,
195 ProcessObject,
196 sizeof(EPROCESS),
197 FALSE);
198 PsIdleProcess->Pcb.DirectoryTableBase.QuadPart = (ULONG_PTR)MmGetPageDirectory();
199 strcpy(PsIdleProcess->ImageFileName, "Idle");
200 PspInheritQuota(PsIdleProcess, NULL);
201
202 /*
203 * Initialize the system process
204 */
205 Status = ObCreateObject(KernelMode,
206 PsProcessType,
207 NULL,
208 KernelMode,
209 NULL,
210 sizeof(EPROCESS),
211 0,
212 0,
213 (PVOID*)&PsInitialSystemProcess);
214 if (!NT_SUCCESS(Status))
215 {
216 DPRINT1("Failed to create the system process object, Status: 0x%x\n", Status);
217 KEBUGCHECK(0);
218 return;
219 }
220
221 /* System threads may run on any processor. */
222 RtlZeroMemory(PsInitialSystemProcess, sizeof(EPROCESS));
223 #ifdef CONFIG_SMP
224 /* FIXME:
225 * Only the boot cpu is initialized. Threads of the
226 * system process should be able to run on all cpus.
227 */
228 PsInitialSystemProcess->Pcb.Affinity = 0xffffffff;
229 #else
230 PsInitialSystemProcess->Pcb.Affinity = KeActiveProcessors;
231 #endif
232 PsInitialSystemProcess->Pcb.IopmOffset = 0xffff;
233 PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIORITY_NORMAL;
234 PsInitialSystemProcess->Pcb.QuantumReset = 6;
235 InitializeListHead(&PsInitialSystemProcess->Pcb.ThreadListHead);
236 KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.Header,
237 ProcessObject,
238 sizeof(EPROCESS),
239 FALSE);
240 KProcess = &PsInitialSystemProcess->Pcb;
241 PspInheritQuota(PsInitialSystemProcess, NULL);
242
243 MmInitializeAddressSpace(PsInitialSystemProcess,
244 &PsInitialSystemProcess->AddressSpace);
245
246 KeInitializeEvent(&PsInitialSystemProcess->LockEvent, SynchronizationEvent, FALSE);
247
248 #if defined(__GNUC__)
249 KProcess->DirectoryTableBase =
250 (LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
251 #else
252 {
253 LARGE_INTEGER dummy;
254 dummy.QuadPart = (LONGLONG)(ULONG)MmGetPageDirectory();
255 KProcess->DirectoryTableBase = dummy;
256 }
257 #endif
258
259 strcpy(PsInitialSystemProcess->ImageFileName, "System");
260
261 PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
262
263 InsertHeadList(&PsActiveProcessHead,
264 &PsInitialSystemProcess->ActiveProcessLinks);
265 InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
266
267 #ifndef SCHED_REWRITE
268 {
269 PTOKEN BootToken;
270
271 /* No parent, this is the Initial System Process. Assign Boot Token */
272 BootToken = SepCreateSystemProcessToken();
273 BootToken->TokenInUse = TRUE;
274 PsInitialSystemProcess->Token.Object = BootToken; /* FIXME */
275 ObReferenceObject(BootToken);
276 }
277 #endif
278 }
279
280 VOID
281 PspPostInitSystemProcess(VOID)
282 {
283 HANDLE_TABLE_ENTRY CidEntry;
284
285 /* this routine is called directly after the exectuive handle tables were
286 initialized. We'll set up the Client ID handle table and assign the system
287 process a PID */
288 PsInitClientIDManagment();
289
290 ObCreateHandleTable(NULL, FALSE, PsInitialSystemProcess);
291 ObpKernelHandleTable = PsInitialSystemProcess->ObjectTable;
292
293 CidEntry.u1.Object = PsInitialSystemProcess;
294 CidEntry.u2.GrantedAccess = 0;
295 PsInitialSystemProcess->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
296
297 if(!PsInitialSystemProcess->UniqueProcessId)
298 {
299 DPRINT1("Failed to create CID handle (unique process id) for the system process!\n");
300 KEBUGCHECK(0);
301 }
302 }
303
304 NTSTATUS
305 STDCALL
306 INIT_FUNCTION
307 PspLookupKernelUserEntryPoints(VOID)
308 {
309 ANSI_STRING ProcedureName;
310 NTSTATUS Status;
311
312 /* Retrieve ntdll's startup address */
313 DPRINT("Getting Entrypoint: %p\n", PspSystemDllBase);
314 RtlInitAnsiString(&ProcedureName, "LdrInitializeThunk");
315 Status = LdrGetProcedureAddress((PVOID)PspSystemDllBase,
316 &ProcedureName,
317 0,
318 &PspSystemDllEntryPoint);
319
320 if (!NT_SUCCESS(Status)) {
321
322 DPRINT1 ("LdrGetProcedureAddress failed (Status %x)\n", Status);
323 return (Status);
324 }
325
326 /* Get User APC Dispatcher */
327 DPRINT("Getting Entrypoint\n");
328 RtlInitAnsiString(&ProcedureName, "KiUserApcDispatcher");
329 Status = LdrGetProcedureAddress((PVOID)PspSystemDllBase,
330 &ProcedureName,
331 0,
332 &KeUserApcDispatcher);
333
334 if (!NT_SUCCESS(Status)) {
335
336 DPRINT1 ("LdrGetProcedureAddress failed (Status %x)\n", Status);
337 return (Status);
338 }
339
340 /* Get Exception Dispatcher */
341 DPRINT("Getting Entrypoint\n");
342 RtlInitAnsiString(&ProcedureName, "KiUserExceptionDispatcher");
343 Status = LdrGetProcedureAddress((PVOID)PspSystemDllBase,
344 &ProcedureName,
345 0,
346 &KeUserExceptionDispatcher);
347
348 if (!NT_SUCCESS(Status)) {
349
350 DPRINT1 ("LdrGetProcedureAddress failed (Status %x)\n", Status);
351 return (Status);
352 }
353
354 /* Get Callback Dispatcher */
355 DPRINT("Getting Entrypoint\n");
356 RtlInitAnsiString(&ProcedureName, "KiUserCallbackDispatcher");
357 Status = LdrGetProcedureAddress((PVOID)PspSystemDllBase,
358 &ProcedureName,
359 0,
360 &KeUserCallbackDispatcher);
361
362 if (!NT_SUCCESS(Status)) {
363
364 DPRINT1 ("LdrGetProcedureAddress failed (Status %x)\n", Status);
365 return (Status);
366 }
367
368 /* Get Raise Exception Dispatcher */
369 DPRINT("Getting Entrypoint\n");
370 RtlInitAnsiString(&ProcedureName, "KiRaiseUserExceptionDispatcher");
371 Status = LdrGetProcedureAddress((PVOID)PspSystemDllBase,
372 &ProcedureName,
373 0,
374 &KeRaiseUserExceptionDispatcher);
375
376 if (!NT_SUCCESS(Status)) {
377
378 DPRINT1 ("LdrGetProcedureAddress failed (Status %x)\n", Status);
379 return (Status);
380 }
381
382 /* Return success */
383 return(STATUS_SUCCESS);
384 }
385
386 NTSTATUS
387 STDCALL
388 PspMapSystemDll(PEPROCESS Process,
389 PVOID *DllBase)
390 {
391 NTSTATUS Status;
392 ULONG ViewSize = 0;
393 PVOID ImageBase = 0;
394
395 /* Map the System DLL */
396 DPRINT("Mapping System DLL\n");
397 Status = MmMapViewOfSection(PspSystemDllSection,
398 Process,
399 (PVOID*)&ImageBase,
400 0,
401 0,
402 NULL,
403 &ViewSize,
404 0,
405 MEM_COMMIT,
406 PAGE_READWRITE);
407
408 if (!NT_SUCCESS(Status)) {
409
410 DPRINT1("Failed to map System DLL Into Process\n");
411 }
412
413 if (DllBase) *DllBase = ImageBase;
414
415 return Status;
416 }
417
418 NTSTATUS
419 STDCALL
420 INIT_FUNCTION
421 PsLocateSystemDll(VOID)
422 {
423 UNICODE_STRING DllPathname = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntdll.dll");
424 OBJECT_ATTRIBUTES FileObjectAttributes;
425 IO_STATUS_BLOCK Iosb;
426 HANDLE FileHandle;
427 HANDLE NTDllSectionHandle;
428 NTSTATUS Status;
429 CHAR BlockBuffer[1024];
430 PIMAGE_DOS_HEADER DosHeader;
431 PIMAGE_NT_HEADERS NTHeaders;
432
433 /* Locate and open NTDLL to determine ImageBase and LdrStartup */
434 InitializeObjectAttributes(&FileObjectAttributes,
435 &DllPathname,
436 0,
437 NULL,
438 NULL);
439
440 DPRINT("Opening NTDLL\n");
441 Status = ZwOpenFile(&FileHandle,
442 FILE_READ_ACCESS,
443 &FileObjectAttributes,
444 &Iosb,
445 FILE_SHARE_READ,
446 FILE_SYNCHRONOUS_IO_NONALERT);
447
448 if (!NT_SUCCESS(Status)) {
449 DPRINT1("NTDLL open failed (Status %x)\n", Status);
450 return Status;
451 }
452
453 /* Load NTDLL is valid */
454 DPRINT("Reading NTDLL\n");
455 Status = ZwReadFile(FileHandle,
456 0,
457 0,
458 0,
459 &Iosb,
460 BlockBuffer,
461 sizeof(BlockBuffer),
462 0,
463 0);
464 if (!NT_SUCCESS(Status) || Iosb.Information != sizeof(BlockBuffer)) {
465
466 DPRINT1("NTDLL header read failed (Status %x)\n", Status);
467 ZwClose(FileHandle);
468 return Status;
469 }
470
471 /* Check if it's valid */
472 DosHeader = (PIMAGE_DOS_HEADER)BlockBuffer;
473 NTHeaders = (PIMAGE_NT_HEADERS)(BlockBuffer + DosHeader->e_lfanew);
474
475 if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE) ||
476 (DosHeader->e_lfanew == 0L) ||
477 (*(PULONG) NTHeaders != IMAGE_NT_SIGNATURE)) {
478
479 DPRINT1("NTDLL format invalid\n");
480 ZwClose(FileHandle);
481 return(STATUS_UNSUCCESSFUL);
482 }
483
484 /* Create a section for NTDLL */
485 DPRINT("Creating section\n");
486 Status = ZwCreateSection(&NTDllSectionHandle,
487 SECTION_ALL_ACCESS,
488 NULL,
489 NULL,
490 PAGE_READONLY,
491 SEC_IMAGE | SEC_COMMIT,
492 FileHandle);
493 if (!NT_SUCCESS(Status)) {
494
495 DPRINT1("NTDLL create section failed (Status %x)\n", Status);
496 ZwClose(FileHandle);
497 return(Status);
498 }
499 ZwClose(FileHandle);
500
501 /* Reference the Section */
502 DPRINT("ObReferenceObjectByHandle section: %d\n", NTDllSectionHandle);
503 Status = ObReferenceObjectByHandle(NTDllSectionHandle,
504 SECTION_ALL_ACCESS,
505 MmSectionObjectType,
506 KernelMode,
507 (PVOID*)&PspSystemDllSection,
508 NULL);
509 if (!NT_SUCCESS(Status)) {
510
511 DPRINT1("NTDLL section reference failed (Status %x)\n", Status);
512 return(Status);
513 }
514
515 /* Map it */
516 PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase);
517 DPRINT("LdrpSystemDllBase: %x\n", PspSystemDllBase);
518
519 /* Now get the Entrypoints */
520 PspLookupKernelUserEntryPoints();
521
522 return STATUS_SUCCESS;
523 }
524
525
526 /**********************************************************************
527 * NAME EXPORTED
528 * PsGetVersion
529 *
530 * DESCRIPTION
531 * Retrieves the current OS version.
532 *
533 * ARGUMENTS
534 * MajorVersion Pointer to a variable that will be set to the
535 * major version of the OS. Can be NULL.
536 *
537 * MinorVersion Pointer to a variable that will be set to the
538 * minor version of the OS. Can be NULL.
539 *
540 * BuildNumber Pointer to a variable that will be set to the
541 * build number of the OS. Can be NULL.
542 *
543 * CSDVersion Pointer to a variable that will be set to the
544 * CSD string of the OS. Can be NULL.
545 *
546 * RETURN VALUE
547 * TRUE OS is a checked build.
548 * FALSE OS is a free build.
549 *
550 * NOTES
551 *
552 * @implemented
553 */
554 BOOLEAN
555 STDCALL
556 PsGetVersion(PULONG MajorVersion OPTIONAL,
557 PULONG MinorVersion OPTIONAL,
558 PULONG BuildNumber OPTIONAL,
559 PUNICODE_STRING CSDVersion OPTIONAL)
560 {
561 if (MajorVersion)
562 *MajorVersion = NtMajorVersion;
563
564 if (MinorVersion)
565 *MinorVersion = NtMinorVersion;
566
567 if (BuildNumber)
568 *BuildNumber = NtBuildNumber;
569
570 if (CSDVersion)
571 {
572 CSDVersion->Length = 0;
573 CSDVersion->MaximumLength = 0;
574 CSDVersion->Buffer = NULL;
575 #if 0
576 CSDVersion->Length = CmCSDVersionString.Length;
577 CSDVersion->MaximumLength = CmCSDVersionString.Maximum;
578 CSDVersion->Buffer = CmCSDVersionString.Buffer;
579 #endif
580 }
581
582 /* Check the High word */
583 return (NtBuildNumber >> 28) == 0xC;
584 }
585
586 /* EOF */