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 CODE_SEG("INIT") 30 SIZE_T 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 CODE_SEG("INIT") 71 VOID 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( 143 _In_ ULONG BootPhase, 144 _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock) 145 { 146 BOOLEAN EnableKd, DisableKdAfterInit = FALSE, BlockEnable; 147 PSTR CommandLine, DebugLine, DebugOptionStart, DebugOptionEnd; 148 STRING ImageName; 149 PLDR_DATA_TABLE_ENTRY LdrEntry; 150 PLIST_ENTRY NextEntry; 151 ULONG i, j, Length; 152 SIZE_T DebugOptionLength; 153 SIZE_T MemSizeMBs; 154 CHAR NameBuffer[256]; 155 PWCHAR Name; 156 157 #if defined(__GNUC__) 158 /* Make gcc happy */ 159 BlockEnable = FALSE; 160 #endif 161 162 /* Check if this is Phase 1 */ 163 if (BootPhase) 164 { 165 /* Just query the performance counter */ 166 KeQueryPerformanceCounter(&KdPerformanceCounterRate); 167 return TRUE; 168 } 169 170 /* Check if we already initialized once */ 171 if (KdDebuggerEnabled) return TRUE; 172 173 /* Set the Debug Routine as the Stub for now */ 174 KiDebugRoutine = KdpStub; 175 176 /* Disable break after symbol load for now */ 177 KdBreakAfterSymbolLoad = FALSE; 178 179 /* Check if the Debugger Data Block was already initialized */ 180 if (!KdpDebuggerDataListHead.Flink) 181 { 182 /* It wasn't...Initialize the KD Data Listhead */ 183 InitializeListHead(&KdpDebuggerDataListHead); 184 185 /* Register the Debugger Data Block */ 186 KdRegisterDebuggerDataBlock(KDBG_TAG, 187 &KdDebuggerDataBlock.Header, 188 sizeof(KdDebuggerDataBlock)); 189 190 /* Fill out the KD Version Block */ 191 KdVersionBlock.MajorVersion = (USHORT)((DBGKD_MAJOR_NT << 8) | (NtBuildNumber >> 28)); 192 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF); 193 194 #ifdef CONFIG_SMP 195 /* This is an MP Build */ 196 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP; 197 #endif 198 199 /* Save Pointers to Loaded Module List and Debugger Data */ 200 KdVersionBlock.PsLoadedModuleList = (ULONG64)(LONG_PTR)&PsLoadedModuleList; 201 KdVersionBlock.DebuggerDataList = (ULONG64)(LONG_PTR)&KdpDebuggerDataListHead; 202 203 /* Set protocol limits */ 204 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange - 205 DbgKdMinimumStateChange; 206 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate - 207 DbgKdMinimumManipulate; 208 KdVersionBlock.Unused[0] = 0; 209 210 /* Link us in the KPCR */ 211 KeGetPcr()->KdVersionBlock = &KdVersionBlock; 212 } 213 214 /* Check if we have a loader block */ 215 if (LoaderBlock) 216 { 217 /* Get the image entry */ 218 LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink, 219 LDR_DATA_TABLE_ENTRY, 220 InLoadOrderLinks); 221 222 /* Save the Kernel Base */ 223 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase; 224 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)LdrEntry->DllBase; 225 226 /* Check if we have a command line */ 227 CommandLine = LoaderBlock->LoadOptions; 228 if (CommandLine) 229 { 230 /* Upcase it */ 231 _strupr(CommandLine); 232 233 /* Assume we'll disable KD */ 234 EnableKd = FALSE; 235 236 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */ 237 if (strstr(CommandLine, "CRASHDEBUG")) 238 { 239 /* Don't enable KD now, but allow it to be enabled later */ 240 KdPitchDebugger = FALSE; 241 } 242 else if (strstr(CommandLine, "NODEBUG")) 243 { 244 /* Don't enable KD and don't let it be enabled later */ 245 KdPitchDebugger = TRUE; 246 } 247 else if ((DebugLine = strstr(CommandLine, "DEBUG")) != NULL) 248 { 249 /* Enable KD */ 250 EnableKd = TRUE; 251 252 /* Check if there are any options */ 253 if (DebugLine[5] == '=') 254 { 255 /* Save pointers */ 256 DebugOptionStart = DebugOptionEnd = &DebugLine[6]; 257 258 /* Scan the string for debug options */ 259 for (;;) 260 { 261 /* Loop until we reach the end of the string */ 262 while (*DebugOptionEnd != ANSI_NULL) 263 { 264 /* Check if this is a comma, a space or a tab */ 265 if ((*DebugOptionEnd == ',') || 266 (*DebugOptionEnd == ' ') || 267 (*DebugOptionEnd == '\t')) 268 { 269 /* 270 * We reached the end of the option or 271 * the end of the string, break out 272 */ 273 break; 274 } 275 else 276 { 277 /* Move on to the next character */ 278 DebugOptionEnd++; 279 } 280 } 281 282 /* Calculate the length of the current option */ 283 DebugOptionLength = (DebugOptionEnd - DebugOptionStart); 284 285 /* 286 * Break out if we reached the last option 287 * or if there were no options at all 288 */ 289 if (!DebugOptionLength) break; 290 291 /* Now check which option this is */ 292 if ((DebugOptionLength == 10) && 293 !(strncmp(DebugOptionStart, "AUTOENABLE", 10))) 294 { 295 /* 296 * Disable the debugger, but 297 * allow it to be reenabled 298 */ 299 DisableKdAfterInit = TRUE; 300 BlockEnable = FALSE; 301 KdAutoEnableOnEvent = TRUE; 302 } 303 else if ((DebugOptionLength == 7) && 304 !(strncmp(DebugOptionStart, "DISABLE", 7))) 305 { 306 /* Disable the debugger */ 307 DisableKdAfterInit = TRUE; 308 BlockEnable = TRUE; 309 KdAutoEnableOnEvent = FALSE; 310 } 311 else if ((DebugOptionLength == 6) && 312 !(strncmp(DebugOptionStart, "NOUMEX", 6))) 313 { 314 /* Ignore user mode exceptions */ 315 KdIgnoreUmExceptions = TRUE; 316 } 317 318 /* 319 * If there are more options then 320 * the next character should be a comma 321 */ 322 if (*DebugOptionEnd != ',') 323 { 324 /* It isn't, break out */ 325 break; 326 } 327 328 /* Move on to the next option */ 329 DebugOptionEnd++; 330 DebugOptionStart = DebugOptionEnd; 331 } 332 } 333 } 334 } 335 else 336 { 337 /* No command line options? Disable debugger by default */ 338 KdPitchDebugger = TRUE; 339 EnableKd = FALSE; 340 } 341 } 342 else 343 { 344 /* Called from a bugcheck or a re-enable. Save the Kernel Base. */ 345 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)PsNtosImageBase; 346 347 /* Unconditionally enable KD */ 348 EnableKd = TRUE; 349 } 350 351 /* Set the Kernel Base in the Data Block */ 352 KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase; 353 354 /* Initialize the debugger if requested */ 355 if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock)))) 356 { 357 /* Now set our real KD routine */ 358 KiDebugRoutine = KdpTrap; 359 360 /* Check if we've already initialized our structures */ 361 if (!KdpDebuggerStructuresInitialized) 362 { 363 /* Set Retries */ 364 KdpContext.KdpDefaultRetries = 20; 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