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)
10 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 KdUpdateDataBlock(VOID
)
22 /* Update the KeUserCallbackDispatcher pointer */
23 KdDebuggerDataBlock
.KeUserCallbackDispatcher
=
24 (ULONG_PTR
)KeUserCallbackDispatcher
;
29 KdRegisterDebuggerDataBlock(IN ULONG Tag
,
30 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader
,
34 PLIST_ENTRY NextEntry
;
35 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader
;
37 /* Acquire the Data Lock */
38 KeAcquireSpinLock(&KdpDataSpinLock
, &OldIrql
);
40 /* Loop the debugger data list */
41 NextEntry
= KdpDebuggerDataListHead
.Flink
;
42 while (NextEntry
!= &KdpDebuggerDataListHead
)
44 /* Get the header for this entry */
45 CurrentHeader
= CONTAINING_RECORD(NextEntry
,
46 DBGKD_DEBUG_DATA_HEADER64
,
49 /* Move to the next one */
50 NextEntry
= NextEntry
->Flink
;
52 /* Check if we already have this data block */
53 if ((CurrentHeader
== DataHeader
) || (CurrentHeader
->OwnerTag
== Tag
))
55 /* Release the lock and fail */
56 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
61 /* Setup the header */
62 DataHeader
->OwnerTag
= Tag
;
63 DataHeader
->Size
= Size
;
65 /* Insert it into the list and release the lock */
66 InsertTailList(&KdpDebuggerDataListHead
, (PLIST_ENTRY
)&DataHeader
->List
);
67 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
73 KdInitSystem(IN ULONG BootPhase
,
74 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
76 BOOLEAN EnableKd
, DisableKdAfterInit
= FALSE
, BlockEnable
;
77 LPSTR CommandLine
, DebugLine
, DebugOptionStart
, DebugOptionEnd
;
79 PLDR_DATA_TABLE_ENTRY LdrEntry
;
80 PLIST_ENTRY NextEntry
;
81 ULONG i
, j
, Length
, DebugOptionLength
;
90 /* Check if this is Phase 1 */
93 /* Just query the performance counter */
94 KeQueryPerformanceCounter(&KdPerformanceCounterRate
);
98 /* Check if we already initialized once */
99 if (KdDebuggerEnabled
) return TRUE
;
101 /* Set the Debug Routine as the Stub for now */
102 KiDebugRoutine
= KdpStub
;
104 /* Disable break after symbol load for now */
105 KdBreakAfterSymbolLoad
= FALSE
;
107 /* Check if the Debugger Data Block was already initialized */
108 if (!KdpDebuggerDataListHead
.Flink
)
110 /* It wasn't...Initialize the KD Data Listhead */
111 InitializeListHead(&KdpDebuggerDataListHead
);
113 /* Register the Debugger Data Block */
114 KdRegisterDebuggerDataBlock(KDBG_TAG
,
115 &KdDebuggerDataBlock
.Header
,
116 sizeof(KdDebuggerDataBlock
));
118 /* Fill out the KD Version Block */
119 KdVersionBlock
.MajorVersion
= (USHORT
)((DBGKD_MAJOR_NT
<< 8) | (NtBuildNumber
>> 28));
120 KdVersionBlock
.MinorVersion
= (USHORT
)(NtBuildNumber
& 0xFFFF);
123 /* This is an MP Build */
124 KdVersionBlock
.Flags
|= DBGKD_VERS_FLAG_MP
;
127 /* Save Pointers to Loaded Module List and Debugger Data */
128 KdVersionBlock
.PsLoadedModuleList
= (ULONG64
)(LONG_PTR
)&PsLoadedModuleList
;
129 KdVersionBlock
.DebuggerDataList
= (ULONG64
)(LONG_PTR
)&KdpDebuggerDataListHead
;
131 /* Set protocol limits */
132 KdVersionBlock
.MaxStateChange
= DbgKdMaximumStateChange
-
133 DbgKdMinimumStateChange
;
134 KdVersionBlock
.MaxManipulate
= DbgKdMaximumManipulate
-
135 DbgKdMinimumManipulate
;
136 KdVersionBlock
.Unused
[0] = 0;
138 /* Link us in the KPCR */
139 KeGetPcr()->KdVersionBlock
= &KdVersionBlock
;
142 /* Check if we have a loader block */
145 /* Get the image entry */
146 LdrEntry
= CONTAINING_RECORD(LoaderBlock
->LoadOrderListHead
.Flink
,
147 LDR_DATA_TABLE_ENTRY
,
150 /* Save the Kernel Base */
151 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
152 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)LdrEntry
->DllBase
;
154 /* Check if we have a command line */
155 CommandLine
= LoaderBlock
->LoadOptions
;
159 _strupr(CommandLine
);
161 /* Assume we'll disable KD */
164 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
165 if (strstr(CommandLine
, "CRASHDEBUG"))
167 /* Don't enable KD now, but allow it to be enabled later */
168 KdPitchDebugger
= FALSE
;
170 else if (strstr(CommandLine
, "NODEBUG"))
172 /* Don't enable KD and don't let it be enabled later */
173 KdPitchDebugger
= TRUE
;
175 else if ((DebugLine
= strstr(CommandLine
, "DEBUG")) != NULL
)
180 /* Check if there are any options */
181 if (DebugLine
[5] == '=')
184 DebugOptionStart
= DebugOptionEnd
= &DebugLine
[6];
186 /* Scan the string for debug options */
189 /* Loop until we reach the end of the string */
190 while (*DebugOptionEnd
!= ANSI_NULL
)
192 /* Check if this is a comma, a space or a tab */
193 if ((*DebugOptionEnd
== ',') ||
194 (*DebugOptionEnd
== ' ') ||
195 (*DebugOptionEnd
== ' '))
198 * We reached the end of the option or
199 * the end of the string, break out
205 /* Move on to the next character */
210 /* Calculate the length of the current option */
211 DebugOptionLength
= ((ULONG_PTR
)DebugOptionEnd
-
212 (ULONG_PTR
)DebugOptionStart
);
215 * Break out if we reached the last option
216 * or if there were no options at all
218 if (!DebugOptionLength
) break;
220 /* Now check which option this is */
221 if ((DebugOptionLength
== 10) &&
222 !(strncmp(DebugOptionStart
, "AUTOENABLE", 10)))
225 * Disable the debugger, but
226 * allow it to be reenabled
228 DisableKdAfterInit
= TRUE
;
230 KdAutoEnableOnEvent
= TRUE
;
232 else if ((DebugOptionLength
== 7) &&
233 !(strncmp(DebugOptionStart
, "DISABLE", 7)))
235 /* Disable the debugger */
236 DisableKdAfterInit
= TRUE
;
238 KdAutoEnableOnEvent
= FALSE
;
240 else if ((DebugOptionLength
== 6) &&
241 !(strncmp(DebugOptionStart
, "NOUMEX", 6)))
243 /* Ignore user mode exceptions */
244 KdIgnoreUmExceptions
= TRUE
;
248 * If there are more options then
249 * the next character should be a comma
251 if (*DebugOptionEnd
!= ',')
253 /* It isn't, break out */
257 /* Move on to the next option */
259 DebugOptionStart
= DebugOptionEnd
;
266 /* No command line options? Disable debugger by default */
267 KdPitchDebugger
= TRUE
;
273 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
274 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)PsNtosImageBase
;
276 /* Unconditionally enable KD */
280 /* Set the Kernel Base in the Data Block */
281 KdDebuggerDataBlock
.KernBase
= (ULONG_PTR
)KdVersionBlock
.KernBase
;
283 /* Initialize the debugger if requested */
284 if ((EnableKd
) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock
))))
286 /* Now set our real KD routine */
287 KiDebugRoutine
= KdpTrap
;
289 /* Check if we've already initialized our structures */
290 if (!KdpDebuggerStructuresInitialized
)
292 /* Set the Debug Switch Routine and Retries*/
293 KdpContext
.KdpDefaultRetries
= 20;
294 KiDebugSwitchRoutine
= KdpSwitchProcessor
;
296 /* Initialize the Time Slip DPC */
297 KeInitializeDpc(&KdpTimeSlipDpc
, KdpTimeSlipDpcRoutine
, NULL
);
298 KeInitializeTimer(&KdpTimeSlipTimer
);
299 ExInitializeWorkItem(&KdpTimeSlipWorkItem
, KdpTimeSlipWork
, NULL
);
301 /* First-time initialization done! */
302 KdpDebuggerStructuresInitialized
= TRUE
;
305 /* Initialize the timer */
306 KdTimerStart
.QuadPart
= 0;
308 /* Officially enable KD */
309 KdPitchDebugger
= FALSE
;
310 KdDebuggerEnabled
= TRUE
;
312 /* Let user-mode know that it's enabled as well */
313 #undef KdDebuggerEnabled
314 SharedUserData
->KdDebuggerEnabled
= TRUE
;
315 #define KdDebuggerEnabled _KdDebuggerEnabled
317 /* Check if the debugger should be disabled initially */
318 if (DisableKdAfterInit
)
321 KdDisableDebuggerWithLock(FALSE
);
324 * Save the enable block state and return initialized
325 * (the debugger is active but disabled).
327 KdBlockEnable
= BlockEnable
;
331 /* Check if we have a loader block */
334 /* Loop boot images */
335 NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
337 while ((NextEntry
!= &LoaderBlock
->LoadOrderListHead
) && (i
< 2))
339 /* Get the image entry */
340 LdrEntry
= CONTAINING_RECORD(NextEntry
,
341 LDR_DATA_TABLE_ENTRY
,
344 /* Generate the image name */
345 Name
= LdrEntry
->FullDllName
.Buffer
;
346 Length
= LdrEntry
->FullDllName
.Length
/ sizeof(WCHAR
);
350 /* Do cheap Unicode to ANSI conversion */
351 NameBuffer
[j
++] = (CHAR
)*Name
++;
352 } while (j
< Length
);
355 NameBuffer
[j
] = ANSI_NULL
;
357 /* Load symbols for image */
358 RtlInitString(&ImageName
, NameBuffer
);
359 DbgLoadImageSymbols(&ImageName
,
361 (ULONG_PTR
)ZwCurrentProcess());
363 /* Go to the next entry */
364 NextEntry
= NextEntry
->Flink
;
369 /* Check for incoming breakin and break on symbol load if we have it*/
370 KdBreakAfterSymbolLoad
= KdPollBreakIn();
374 /* Disable debugger */
375 KdDebuggerNotPresent
= TRUE
;
378 /* Return initialized */