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