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)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
19 KdUpdateDataBlock(VOID
)
21 /* Update the KeUserCallbackDispatcher pointer */
22 KdDebuggerDataBlock
.KeUserCallbackDispatcher
=
23 (ULONG_PTR
)KeUserCallbackDispatcher
;
28 KdRegisterDebuggerDataBlock(IN ULONG Tag
,
29 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader
,
33 PLIST_ENTRY NextEntry
;
34 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader
;
36 /* Acquire the Data Lock */
37 KeAcquireSpinLock(&KdpDataSpinLock
, &OldIrql
);
39 /* Loop the debugger data list */
40 NextEntry
= KdpDebuggerDataListHead
.Flink
;
41 while (NextEntry
!= &KdpDebuggerDataListHead
)
43 /* Get the header for this entry */
44 CurrentHeader
= CONTAINING_RECORD(NextEntry
,
45 DBGKD_DEBUG_DATA_HEADER64
,
48 /* Move to the next one */
49 NextEntry
= NextEntry
->Flink
;
51 /* Check if we already have this data block */
52 if ((CurrentHeader
== DataHeader
) || (CurrentHeader
->OwnerTag
== Tag
))
54 /* Release the lock and fail */
55 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
60 /* Setup the header */
61 DataHeader
->OwnerTag
= Tag
;
62 DataHeader
->Size
= Size
;
64 /* Insert it into the list and release the lock */
65 InsertTailList(&KdpDebuggerDataListHead
, (PLIST_ENTRY
)&DataHeader
->List
);
66 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
72 KdInitSystem(IN ULONG BootPhase
,
73 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
75 BOOLEAN EnableKd
, DisableKdAfterInit
= FALSE
, BlockEnable
;
76 LPSTR CommandLine
, DebugLine
, DebugOptionStart
, DebugOptionEnd
;
77 ANSI_STRING ImageName
;
78 PLDR_DATA_TABLE_ENTRY LdrEntry
;
79 PLIST_ENTRY NextEntry
;
80 ULONG i
, j
, Length
, DebugOptionLength
;
89 /* Check if this is Phase 1 */
92 /* Just query the performance counter */
93 KeQueryPerformanceCounter(&KdPerformanceCounterRate
);
97 /* Check if we already initialized once */
98 if (KdDebuggerEnabled
) return TRUE
;
100 /* Set the Debug Routine as the Stub for now */
101 KiDebugRoutine
= KdpStub
;
103 /* Disable break after symbol load for now */
104 KdBreakAfterSymbolLoad
= FALSE
;
106 /* Check if the Debugger Data Block was already initialized */
107 if (!KdpDebuggerDataListHead
.Flink
)
109 /* It wasn't...Initialize the KD Data Listhead */
110 InitializeListHead(&KdpDebuggerDataListHead
);
112 /* Register the Debugger Data Block */
113 KdRegisterDebuggerDataBlock(KDBG_TAG
,
114 &KdDebuggerDataBlock
.Header
,
115 sizeof(KdDebuggerDataBlock
));
117 /* Fill out the KD Version Block */
118 KdVersionBlock
.MajorVersion
= (USHORT
)(NtBuildNumber
>> 28);
119 KdVersionBlock
.MinorVersion
= (USHORT
)(NtBuildNumber
& 0xFFFF);
122 /* This is an MP Build */
123 KdVersionBlock
.Flags
|= DBGKD_VERS_FLAG_MP
;
126 /* Save Pointers to Loaded Module List and Debugger Data */
127 KdVersionBlock
.PsLoadedModuleList
= (ULONG64
)(LONG_PTR
)&PsLoadedModuleList
;
128 KdVersionBlock
.DebuggerDataList
= (ULONG64
)(LONG_PTR
)&KdpDebuggerDataListHead
;
130 /* Set protocol limits */
131 KdVersionBlock
.MaxStateChange
= DbgKdMaximumStateChange
-
132 DbgKdMinimumStateChange
;
133 KdVersionBlock
.MaxManipulate
= DbgKdMaximumManipulate
-
134 DbgKdMinimumManipulate
;
135 KdVersionBlock
.Unused
[0] = 0;
137 /* Link us in the KPCR */
138 KeGetPcr()->KdVersionBlock
= &KdVersionBlock
;
141 /* Check if we have a loader block */
144 /* Get the image entry */
145 LdrEntry
= CONTAINING_RECORD(LoaderBlock
->LoadOrderListHead
.Flink
,
146 LDR_DATA_TABLE_ENTRY
,
149 /* Save the Kernel Base */
150 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
151 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)LdrEntry
->DllBase
;
153 /* Check if we have a command line */
154 CommandLine
= LoaderBlock
->LoadOptions
;
158 _strupr(CommandLine
);
160 /* Assume we'll disable KD */
163 /* Check for CRASHDEBUG and NODEBUG */
164 if (strstr(CommandLine
, "CRASHDEBUG")) KdPitchDebugger
= FALSE
;
165 if (strstr(CommandLine
, "NODEBUG")) KdPitchDebugger
= TRUE
;
167 /* Check if DEBUG was on */
168 DebugLine
= strstr(CommandLine
, "DEBUG");
174 /* Check if there are any options */
175 if (DebugLine
[5] == '=')
178 DebugOptionStart
= DebugOptionEnd
= &DebugLine
[6];
180 /* Scan the string for debug options */
183 /* Loop until we reach the end of the string */
184 while (*DebugOptionEnd
!= ANSI_NULL
)
186 /* Check if this is a comma, a space or a tab */
187 if ((*DebugOptionEnd
== ',') ||
188 (*DebugOptionEnd
== ' ') ||
189 (*DebugOptionEnd
== ' '))
192 * We reached the end of the option or
193 * the end of the string, break out
199 /* Move on to the next character */
204 /* Calculate the length of the current option */
205 DebugOptionLength
= ((ULONG_PTR
)DebugOptionEnd
-
206 (ULONG_PTR
)DebugOptionStart
);
209 * Break out if we reached the last option
210 * or if there were no options at all
212 if (!DebugOptionLength
) break;
214 /* Now check which option this is */
215 if ((DebugOptionLength
== 10) &&
216 !(strncmp(DebugOptionStart
, "AUTOENABLE", 10)))
219 * Disable the debugger, but
220 * allow it to be reenabled
222 DisableKdAfterInit
= TRUE
;
224 KdAutoEnableOnEvent
= TRUE
;
226 else if ((DebugOptionLength
== 7) &&
227 !(strncmp(DebugOptionStart
, "DISABLE", 7)))
229 /* Disable the debugger */
230 DisableKdAfterInit
= TRUE
;
232 KdAutoEnableOnEvent
= FALSE
;
234 else if ((DebugOptionLength
== 6) &&
235 !(strncmp(DebugOptionStart
, "NOUMEX", 6)))
237 /* Ignore user mode exceptions */
238 KdIgnoreUmExceptions
= TRUE
;
242 * If there are more options then
243 * the next character should be a comma
245 if (*DebugOptionEnd
!= ',')
247 /* It isn't, break out */
251 /* Move on to the next option */
253 DebugOptionStart
= DebugOptionEnd
;
260 /* No command line options? Disable debugger by default */
261 KdPitchDebugger
= TRUE
;
267 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
268 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)PsNtosImageBase
;
270 /* Unconditionally enable KD */
274 /* Set the Kernel Base in the Data Block */
275 KdDebuggerDataBlock
.KernBase
= (ULONG_PTR
)KdVersionBlock
.KernBase
;
277 /* Initialize the debugger if requested */
278 if ((EnableKd
) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock
))))
280 /* Now set our real KD routine */
281 KiDebugRoutine
= KdpTrap
;
283 /* Check if we've already initialized our structures */
284 if (!KdpDebuggerStructuresInitialized
)
286 /* Set the Debug Switch Routine and Retries*/
287 KdpContext
.KdpDefaultRetries
= 20;
288 KiDebugSwitchRoutine
= KdpSwitchProcessor
;
290 /* Initialize the Time Slip DPC */
291 KeInitializeDpc(&KdpTimeSlipDpc
, KdpTimeSlipDpcRoutine
, NULL
);
292 KeInitializeTimer(&KdpTimeSlipTimer
);
293 ExInitializeWorkItem(&KdpTimeSlipWorkItem
, KdpTimeSlipWork
, NULL
);
295 /* First-time initialization done! */
296 KdpDebuggerStructuresInitialized
= TRUE
;
299 /* Initialize the timer */
300 KdTimerStart
.QuadPart
= 0;
302 /* Officially enable KD */
303 KdPitchDebugger
= FALSE
;
304 KdDebuggerEnabled
= TRUE
;
306 /* Let user-mode know that it's enabled as well */
307 #undef KdDebuggerEnabled
308 SharedUserData
->KdDebuggerEnabled
= TRUE
;
309 #define KdDebuggerEnabled _KdDebuggerEnabled
311 /* Check if the debugger should be disabled initially */
312 if (DisableKdAfterInit
)
315 KdDisableDebuggerWithLock(FALSE
);
318 * Save the enable block state and return initialized
319 * (the debugger is active but disabled).
321 KdBlockEnable
= BlockEnable
;
325 /* Check if we have a loader block */
328 /* Loop boot images */
329 NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
331 while ((NextEntry
!= &LoaderBlock
->LoadOrderListHead
) && (i
< 2))
333 /* Get the image entry */
334 LdrEntry
= CONTAINING_RECORD(NextEntry
,
335 LDR_DATA_TABLE_ENTRY
,
338 /* Generate the image name */
339 Name
= LdrEntry
->FullDllName
.Buffer
;
340 Length
= LdrEntry
->FullDllName
.Length
/ sizeof(WCHAR
);
344 /* Do cheap Unicode to ANSI conversion */
345 NameBuffer
[j
++] = (CHAR
)*Name
++;
346 } while (j
< Length
);
349 NameBuffer
[j
] = ANSI_NULL
;
351 /* Load symbols for image */
352 RtlInitAnsiString(&ImageName
, NameBuffer
);
353 DbgLoadImageSymbols(&ImageName
, LdrEntry
->DllBase
, -1);
355 /* Go to the next entry */
356 NextEntry
= NextEntry
->Flink
;
361 /* Check for incoming breakin and break on symbol load if we have it*/
362 KdBreakAfterSymbolLoad
= KdPollBreakIn();
366 /* Disable debugger */
367 KdDebuggerNotPresent
= TRUE
;
370 /* Return initialized */