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