1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/kd64/kdinit.c 5 * PURPOSE: KD64 Initialization Code 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Stefan Ginsberg (stefan.ginsberg@reactos.org) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #include <reactos/buildno.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* UTILITY FUNCTIONS *********************************************************/ 18 19 /* 20 * Get the total size of the memory before 21 * Mm is initialized, by counting the number 22 * of physical pages. Useful for debug logging. 23 * 24 * Strongly inspired by: 25 * mm\ARM3\mminit.c : MiScanMemoryDescriptors(...) 26 * 27 * See also: kd\kdio.c 28 */ 29 static SIZE_T 30 INIT_FUNCTION 31 KdpGetMemorySizeInMBs(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 32 { 33 PLIST_ENTRY ListEntry; 34 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; 35 SIZE_T NumberOfPhysicalPages = 0; 36 37 /* Loop the memory descriptors */ 38 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 39 ListEntry != &LoaderBlock->MemoryDescriptorListHead; 40 ListEntry = ListEntry->Flink) 41 { 42 /* Get the descriptor */ 43 Descriptor = CONTAINING_RECORD(ListEntry, 44 MEMORY_ALLOCATION_DESCRIPTOR, 45 ListEntry); 46 47 /* Check if this is invisible memory */ 48 if ((Descriptor->MemoryType == LoaderFirmwarePermanent) || 49 (Descriptor->MemoryType == LoaderSpecialMemory) || 50 (Descriptor->MemoryType == LoaderHALCachedMemory) || 51 (Descriptor->MemoryType == LoaderBBTMemory)) 52 { 53 /* Skip this descriptor */ 54 continue; 55 } 56 57 /* Check if this is bad memory */ 58 if (Descriptor->MemoryType != LoaderBad) 59 { 60 /* Count this in the total of pages */ 61 NumberOfPhysicalPages += Descriptor->PageCount; 62 } 63 } 64 65 /* Round size up. Assumed to better match actual physical RAM size */ 66 return ALIGN_UP_BY(NumberOfPhysicalPages * PAGE_SIZE, 1024 * 1024) / (1024 * 1024); 67 } 68 69 /* See also: kd\kdio.c */ 70 static VOID 71 INIT_FUNCTION 72 KdpPrintBanner(IN SIZE_T MemSizeMBs) 73 { 74 DPRINT1("-----------------------------------------------------\n"); 75 DPRINT1("ReactOS " KERNEL_VERSION_STR " (Build " KERNEL_VERSION_BUILD_STR ") (Commit " KERNEL_VERSION_COMMIT_HASH ")\n"); 76 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs); 77 78 if (KeLoaderBlock) 79 { 80 DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions); 81 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName, KeLoaderBlock->NtHalPathName, KeLoaderBlock->ArcHalDeviceName, KeLoaderBlock->NtBootPathName); 82 } 83 } 84 85 /* FUNCTIONS *****************************************************************/ 86 87 VOID 88 NTAPI 89 KdUpdateDataBlock(VOID) 90 { 91 /* Update the KeUserCallbackDispatcher pointer */ 92 KdDebuggerDataBlock.KeUserCallbackDispatcher = 93 (ULONG_PTR)KeUserCallbackDispatcher; 94 } 95 96 BOOLEAN 97 NTAPI 98 KdRegisterDebuggerDataBlock(IN ULONG Tag, 99 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader, 100 IN ULONG Size) 101 { 102 KIRQL OldIrql; 103 PLIST_ENTRY NextEntry; 104 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader; 105 106 /* Acquire the Data Lock */ 107 KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql); 108 109 /* Loop the debugger data list */ 110 NextEntry = KdpDebuggerDataListHead.Flink; 111 while (NextEntry != &KdpDebuggerDataListHead) 112 { 113 /* Get the header for this entry */ 114 CurrentHeader = CONTAINING_RECORD(NextEntry, 115 DBGKD_DEBUG_DATA_HEADER64, 116 List); 117 118 /* Move to the next one */ 119 NextEntry = NextEntry->Flink; 120 121 /* Check if we already have this data block */ 122 if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag)) 123 { 124 /* Release the lock and fail */ 125 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql); 126 return FALSE; 127 } 128 } 129 130 /* Setup the header */ 131 DataHeader->OwnerTag = Tag; 132 DataHeader->Size = Size; 133 134 /* Insert it into the list and release the lock */ 135 InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List); 136 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql); 137 return TRUE; 138 } 139 140 BOOLEAN 141 NTAPI 142 KdInitSystem(IN ULONG BootPhase, 143 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 144 { 145 BOOLEAN EnableKd, DisableKdAfterInit = FALSE, BlockEnable; 146 LPSTR CommandLine, DebugLine, DebugOptionStart, DebugOptionEnd; 147 STRING ImageName; 148 PLDR_DATA_TABLE_ENTRY LdrEntry; 149 PLIST_ENTRY NextEntry; 150 ULONG i, j, Length; 151 SIZE_T DebugOptionLength; 152 SIZE_T MemSizeMBs; 153 CHAR NameBuffer[256]; 154 PWCHAR Name; 155 156 #if defined(__GNUC__) 157 /* Make gcc happy */ 158 BlockEnable = FALSE; 159 #endif 160 161 /* Check if this is Phase 1 */ 162 if (BootPhase) 163 { 164 /* Just query the performance counter */ 165 KeQueryPerformanceCounter(&KdPerformanceCounterRate); 166 return TRUE; 167 } 168 169 /* Check if we already initialized once */ 170 if (KdDebuggerEnabled) return TRUE; 171 172 /* Set the Debug Routine as the Stub for now */ 173 KiDebugRoutine = KdpStub; 174 175 /* Disable break after symbol load for now */ 176 KdBreakAfterSymbolLoad = FALSE; 177 178 /* Check if the Debugger Data Block was already initialized */ 179 if (!KdpDebuggerDataListHead.Flink) 180 { 181 /* It wasn't...Initialize the KD Data Listhead */ 182 InitializeListHead(&KdpDebuggerDataListHead); 183 184 /* Register the Debugger Data Block */ 185 KdRegisterDebuggerDataBlock(KDBG_TAG, 186 &KdDebuggerDataBlock.Header, 187 sizeof(KdDebuggerDataBlock)); 188 189 /* Fill out the KD Version Block */ 190 KdVersionBlock.MajorVersion = (USHORT)((DBGKD_MAJOR_NT << 8) | (NtBuildNumber >> 28)); 191 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF); 192 193 #ifdef CONFIG_SMP 194 /* This is an MP Build */ 195 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP; 196 #endif 197 198 /* Save Pointers to Loaded Module List and Debugger Data */ 199 KdVersionBlock.PsLoadedModuleList = (ULONG64)(LONG_PTR)&PsLoadedModuleList; 200 KdVersionBlock.DebuggerDataList = (ULONG64)(LONG_PTR)&KdpDebuggerDataListHead; 201 202 /* Set protocol limits */ 203 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange - 204 DbgKdMinimumStateChange; 205 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate - 206 DbgKdMinimumManipulate; 207 KdVersionBlock.Unused[0] = 0; 208 209 /* Link us in the KPCR */ 210 KeGetPcr()->KdVersionBlock = &KdVersionBlock; 211 } 212 213 /* Check if we have a loader block */ 214 if (LoaderBlock) 215 { 216 /* Get the image entry */ 217 LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink, 218 LDR_DATA_TABLE_ENTRY, 219 InLoadOrderLinks); 220 221 /* Save the Kernel Base */ 222 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase; 223 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)LdrEntry->DllBase; 224 225 /* Check if we have a command line */ 226 CommandLine = LoaderBlock->LoadOptions; 227 if (CommandLine) 228 { 229 /* Upcase it */ 230 _strupr(CommandLine); 231 232 /* Assume we'll disable KD */ 233 EnableKd = FALSE; 234 235 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */ 236 if (strstr(CommandLine, "CRASHDEBUG")) 237 { 238 /* Don't enable KD now, but allow it to be enabled later */ 239 KdPitchDebugger = FALSE; 240 } 241 else if (strstr(CommandLine, "NODEBUG")) 242 { 243 /* Don't enable KD and don't let it be enabled later */ 244 KdPitchDebugger = TRUE; 245 } 246 else if ((DebugLine = strstr(CommandLine, "DEBUG")) != NULL) 247 { 248 /* Enable KD */ 249 EnableKd = TRUE; 250 251 /* Check if there are any options */ 252 if (DebugLine[5] == '=') 253 { 254 /* Save pointers */ 255 DebugOptionStart = DebugOptionEnd = &DebugLine[6]; 256 257 /* Scan the string for debug options */ 258 for (;;) 259 { 260 /* Loop until we reach the end of the string */ 261 while (*DebugOptionEnd != ANSI_NULL) 262 { 263 /* Check if this is a comma, a space or a tab */ 264 if ((*DebugOptionEnd == ',') || 265 (*DebugOptionEnd == ' ') || 266 (*DebugOptionEnd == '\t')) 267 { 268 /* 269 * We reached the end of the option or 270 * the end of the string, break out 271 */ 272 break; 273 } 274 else 275 { 276 /* Move on to the next character */ 277 DebugOptionEnd++; 278 } 279 } 280 281 /* Calculate the length of the current option */ 282 DebugOptionLength = (DebugOptionEnd - DebugOptionStart); 283 284 /* 285 * Break out if we reached the last option 286 * or if there were no options at all 287 */ 288 if (!DebugOptionLength) break; 289 290 /* Now check which option this is */ 291 if ((DebugOptionLength == 10) && 292 !(strncmp(DebugOptionStart, "AUTOENABLE", 10))) 293 { 294 /* 295 * Disable the debugger, but 296 * allow it to be reenabled 297 */ 298 DisableKdAfterInit = TRUE; 299 BlockEnable = FALSE; 300 KdAutoEnableOnEvent = TRUE; 301 } 302 else if ((DebugOptionLength == 7) && 303 !(strncmp(DebugOptionStart, "DISABLE", 7))) 304 { 305 /* Disable the debugger */ 306 DisableKdAfterInit = TRUE; 307 BlockEnable = TRUE; 308 KdAutoEnableOnEvent = FALSE; 309 } 310 else if ((DebugOptionLength == 6) && 311 !(strncmp(DebugOptionStart, "NOUMEX", 6))) 312 { 313 /* Ignore user mode exceptions */ 314 KdIgnoreUmExceptions = TRUE; 315 } 316 317 /* 318 * If there are more options then 319 * the next character should be a comma 320 */ 321 if (*DebugOptionEnd != ',') 322 { 323 /* It isn't, break out */ 324 break; 325 } 326 327 /* Move on to the next option */ 328 DebugOptionEnd++; 329 DebugOptionStart = DebugOptionEnd; 330 } 331 } 332 } 333 } 334 else 335 { 336 /* No command line options? Disable debugger by default */ 337 KdPitchDebugger = TRUE; 338 EnableKd = FALSE; 339 } 340 } 341 else 342 { 343 /* Called from a bugcheck or a re-enable. Save the Kernel Base */ 344 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)PsNtosImageBase; 345 346 /* Unconditionally enable KD */ 347 EnableKd = TRUE; 348 } 349 350 /* Set the Kernel Base in the Data Block */ 351 KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase; 352 353 /* Initialize the debugger if requested */ 354 if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock)))) 355 { 356 /* Now set our real KD routine */ 357 KiDebugRoutine = KdpTrap; 358 359 /* Check if we've already initialized our structures */ 360 if (!KdpDebuggerStructuresInitialized) 361 { 362 /* Set the Debug Switch Routine and Retries */ 363 KdpContext.KdpDefaultRetries = 20; 364 KiDebugSwitchRoutine = KdpSwitchProcessor; 365 366 /* Initialize breakpoints owed flag and table */ 367 KdpOweBreakpoint = FALSE; 368 for (i = 0; i < KD_BREAKPOINT_MAX; i++) 369 { 370 KdpBreakpointTable[i].Flags = 0; 371 KdpBreakpointTable[i].DirectoryTableBase = 0; 372 KdpBreakpointTable[i].Address = NULL; 373 } 374 375 /* Initialize the Time Slip DPC */ 376 KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL); 377 KeInitializeTimer(&KdpTimeSlipTimer); 378 ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL); 379 380 /* First-time initialization done! */ 381 KdpDebuggerStructuresInitialized = TRUE; 382 } 383 384 /* Initialize the timer */ 385 KdTimerStart.QuadPart = 0; 386 387 /* Officially enable KD */ 388 KdPitchDebugger = FALSE; 389 KdDebuggerEnabled = TRUE; 390 391 /* Let user-mode know that it's enabled as well */ 392 SharedUserData->KdDebuggerEnabled = TRUE; 393 394 /* Display separator + ReactOS version at start of the debug log */ 395 MemSizeMBs = KdpGetMemorySizeInMBs(KeLoaderBlock); 396 KdpPrintBanner(MemSizeMBs); 397 398 /* Check if the debugger should be disabled initially */ 399 if (DisableKdAfterInit) 400 { 401 /* Disable it */ 402 KdDisableDebuggerWithLock(FALSE); 403 404 /* 405 * Save the enable block state and return initialized 406 * (the debugger is active but disabled). 407 */ 408 KdBlockEnable = BlockEnable; 409 return TRUE; 410 } 411 412 /* Check if we have a loader block */ 413 if (LoaderBlock) 414 { 415 /* Loop boot images */ 416 NextEntry = LoaderBlock->LoadOrderListHead.Flink; 417 i = 0; 418 while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2)) 419 { 420 /* Get the image entry */ 421 LdrEntry = CONTAINING_RECORD(NextEntry, 422 LDR_DATA_TABLE_ENTRY, 423 InLoadOrderLinks); 424 425 /* Generate the image name */ 426 Name = LdrEntry->FullDllName.Buffer; 427 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR); 428 j = 0; 429 do 430 { 431 /* Do cheap Unicode to ANSI conversion */ 432 NameBuffer[j++] = (CHAR)*Name++; 433 } while (j < Length); 434 435 /* Null-terminate */ 436 NameBuffer[j] = ANSI_NULL; 437 438 /* Load symbols for image */ 439 RtlInitString(&ImageName, NameBuffer); 440 DbgLoadImageSymbols(&ImageName, 441 LdrEntry->DllBase, 442 (ULONG_PTR)PsGetCurrentProcessId()); 443 444 /* Go to the next entry */ 445 NextEntry = NextEntry->Flink; 446 i++; 447 } 448 } 449 450 /* Check for incoming breakin and break on symbol load if we have it */ 451 KdBreakAfterSymbolLoad = KdPollBreakIn(); 452 } 453 else 454 { 455 /* Disable debugger */ 456 KdDebuggerNotPresent = TRUE; 457 } 458 459 /* Return initialized */ 460 return TRUE; 461 } 462