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 ******************************************************************/
13 #include <reactos/buildno.h>
17 /* UTILITY FUNCTIONS *********************************************************/
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.
24 * Strongly inspired by:
25 * mm\ARM3\mminit.c : MiScanMemoryDescriptors(...)
31 KdpGetMemorySizeInMBs(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
33 PLIST_ENTRY ListEntry
;
34 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
35 SIZE_T NumberOfPhysicalPages
= 0;
37 /* Loop the memory descriptors */
38 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
39 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
40 ListEntry
= ListEntry
->Flink
)
42 /* Get the descriptor */
43 Descriptor
= CONTAINING_RECORD(ListEntry
,
44 MEMORY_ALLOCATION_DESCRIPTOR
,
47 /* Check if this is invisible memory */
48 if ((Descriptor
->MemoryType
== LoaderFirmwarePermanent
) ||
49 (Descriptor
->MemoryType
== LoaderSpecialMemory
) ||
50 (Descriptor
->MemoryType
== LoaderHALCachedMemory
) ||
51 (Descriptor
->MemoryType
== LoaderBBTMemory
))
53 /* Skip this descriptor */
57 /* Check if this is bad memory */
58 if (Descriptor
->MemoryType
!= LoaderBad
)
60 /* Count this in the total of pages */
61 NumberOfPhysicalPages
+= Descriptor
->PageCount
;
65 /* Round size up. Assumed to better match actual physical RAM size */
66 return ALIGN_UP_BY(NumberOfPhysicalPages
* PAGE_SIZE
, 1024 * 1024) / (1024 * 1024);
69 /* See also: kd\kdio.c */
72 KdpPrintBanner(IN SIZE_T MemSizeMBs
)
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
);
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
);
85 /* FUNCTIONS *****************************************************************/
89 KdUpdateDataBlock(VOID
)
91 /* Update the KeUserCallbackDispatcher pointer */
92 KdDebuggerDataBlock
.KeUserCallbackDispatcher
=
93 (ULONG_PTR
)KeUserCallbackDispatcher
;
98 KdRegisterDebuggerDataBlock(IN ULONG Tag
,
99 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader
,
103 PLIST_ENTRY NextEntry
;
104 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader
;
106 /* Acquire the Data Lock */
107 KeAcquireSpinLock(&KdpDataSpinLock
, &OldIrql
);
109 /* Loop the debugger data list */
110 NextEntry
= KdpDebuggerDataListHead
.Flink
;
111 while (NextEntry
!= &KdpDebuggerDataListHead
)
113 /* Get the header for this entry */
114 CurrentHeader
= CONTAINING_RECORD(NextEntry
,
115 DBGKD_DEBUG_DATA_HEADER64
,
118 /* Move to the next one */
119 NextEntry
= NextEntry
->Flink
;
121 /* Check if we already have this data block */
122 if ((CurrentHeader
== DataHeader
) || (CurrentHeader
->OwnerTag
== Tag
))
124 /* Release the lock and fail */
125 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
130 /* Setup the header */
131 DataHeader
->OwnerTag
= Tag
;
132 DataHeader
->Size
= Size
;
134 /* Insert it into the list and release the lock */
135 InsertTailList(&KdpDebuggerDataListHead
, (PLIST_ENTRY
)&DataHeader
->List
);
136 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
142 KdInitSystem(IN ULONG BootPhase
,
143 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
145 BOOLEAN EnableKd
, DisableKdAfterInit
= FALSE
, BlockEnable
;
146 LPSTR CommandLine
, DebugLine
, DebugOptionStart
, DebugOptionEnd
;
148 PLDR_DATA_TABLE_ENTRY LdrEntry
;
149 PLIST_ENTRY NextEntry
;
151 SIZE_T DebugOptionLength
;
153 CHAR NameBuffer
[256];
156 #if defined(__GNUC__)
161 /* Check if this is Phase 1 */
164 /* Just query the performance counter */
165 KeQueryPerformanceCounter(&KdPerformanceCounterRate
);
169 /* Check if we already initialized once */
170 if (KdDebuggerEnabled
) return TRUE
;
172 /* Set the Debug Routine as the Stub for now */
173 KiDebugRoutine
= KdpStub
;
175 /* Disable break after symbol load for now */
176 KdBreakAfterSymbolLoad
= FALSE
;
178 /* Check if the Debugger Data Block was already initialized */
179 if (!KdpDebuggerDataListHead
.Flink
)
181 /* It wasn't...Initialize the KD Data Listhead */
182 InitializeListHead(&KdpDebuggerDataListHead
);
184 /* Register the Debugger Data Block */
185 KdRegisterDebuggerDataBlock(KDBG_TAG
,
186 &KdDebuggerDataBlock
.Header
,
187 sizeof(KdDebuggerDataBlock
));
189 /* Fill out the KD Version Block */
190 KdVersionBlock
.MajorVersion
= (USHORT
)((DBGKD_MAJOR_NT
<< 8) | (NtBuildNumber
>> 28));
191 KdVersionBlock
.MinorVersion
= (USHORT
)(NtBuildNumber
& 0xFFFF);
194 /* This is an MP Build */
195 KdVersionBlock
.Flags
|= DBGKD_VERS_FLAG_MP
;
198 /* Save Pointers to Loaded Module List and Debugger Data */
199 KdVersionBlock
.PsLoadedModuleList
= (ULONG64
)(LONG_PTR
)&PsLoadedModuleList
;
200 KdVersionBlock
.DebuggerDataList
= (ULONG64
)(LONG_PTR
)&KdpDebuggerDataListHead
;
202 /* Set protocol limits */
203 KdVersionBlock
.MaxStateChange
= DbgKdMaximumStateChange
-
204 DbgKdMinimumStateChange
;
205 KdVersionBlock
.MaxManipulate
= DbgKdMaximumManipulate
-
206 DbgKdMinimumManipulate
;
207 KdVersionBlock
.Unused
[0] = 0;
209 /* Link us in the KPCR */
210 KeGetPcr()->KdVersionBlock
= &KdVersionBlock
;
213 /* Check if we have a loader block */
216 /* Get the image entry */
217 LdrEntry
= CONTAINING_RECORD(LoaderBlock
->LoadOrderListHead
.Flink
,
218 LDR_DATA_TABLE_ENTRY
,
221 /* Save the Kernel Base */
222 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
223 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)LdrEntry
->DllBase
;
225 /* Check if we have a command line */
226 CommandLine
= LoaderBlock
->LoadOptions
;
230 _strupr(CommandLine
);
232 /* Assume we'll disable KD */
235 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
236 if (strstr(CommandLine
, "CRASHDEBUG"))
238 /* Don't enable KD now, but allow it to be enabled later */
239 KdPitchDebugger
= FALSE
;
241 else if (strstr(CommandLine
, "NODEBUG"))
243 /* Don't enable KD and don't let it be enabled later */
244 KdPitchDebugger
= TRUE
;
246 else if ((DebugLine
= strstr(CommandLine
, "DEBUG")) != NULL
)
251 /* Check if there are any options */
252 if (DebugLine
[5] == '=')
255 DebugOptionStart
= DebugOptionEnd
= &DebugLine
[6];
257 /* Scan the string for debug options */
260 /* Loop until we reach the end of the string */
261 while (*DebugOptionEnd
!= ANSI_NULL
)
263 /* Check if this is a comma, a space or a tab */
264 if ((*DebugOptionEnd
== ',') ||
265 (*DebugOptionEnd
== ' ') ||
266 (*DebugOptionEnd
== '\t'))
269 * We reached the end of the option or
270 * the end of the string, break out
276 /* Move on to the next character */
281 /* Calculate the length of the current option */
282 DebugOptionLength
= (DebugOptionEnd
- DebugOptionStart
);
285 * Break out if we reached the last option
286 * or if there were no options at all
288 if (!DebugOptionLength
) break;
290 /* Now check which option this is */
291 if ((DebugOptionLength
== 10) &&
292 !(strncmp(DebugOptionStart
, "AUTOENABLE", 10)))
295 * Disable the debugger, but
296 * allow it to be reenabled
298 DisableKdAfterInit
= TRUE
;
300 KdAutoEnableOnEvent
= TRUE
;
302 else if ((DebugOptionLength
== 7) &&
303 !(strncmp(DebugOptionStart
, "DISABLE", 7)))
305 /* Disable the debugger */
306 DisableKdAfterInit
= TRUE
;
308 KdAutoEnableOnEvent
= FALSE
;
310 else if ((DebugOptionLength
== 6) &&
311 !(strncmp(DebugOptionStart
, "NOUMEX", 6)))
313 /* Ignore user mode exceptions */
314 KdIgnoreUmExceptions
= TRUE
;
318 * If there are more options then
319 * the next character should be a comma
321 if (*DebugOptionEnd
!= ',')
323 /* It isn't, break out */
327 /* Move on to the next option */
329 DebugOptionStart
= DebugOptionEnd
;
336 /* No command line options? Disable debugger by default */
337 KdPitchDebugger
= TRUE
;
343 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
344 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)PsNtosImageBase
;
346 /* Unconditionally enable KD */
350 /* Set the Kernel Base in the Data Block */
351 KdDebuggerDataBlock
.KernBase
= (ULONG_PTR
)KdVersionBlock
.KernBase
;
353 /* Initialize the debugger if requested */
354 if (EnableKd
&& (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock
))))
356 /* Now set our real KD routine */
357 KiDebugRoutine
= KdpTrap
;
359 /* Check if we've already initialized our structures */
360 if (!KdpDebuggerStructuresInitialized
)
362 /* Set the Debug Switch Routine and Retries */
363 KdpContext
.KdpDefaultRetries
= 20;
364 KiDebugSwitchRoutine
= KdpSwitchProcessor
;
366 /* Initialize breakpoints owed flag and table */
367 KdpOweBreakpoint
= FALSE
;
368 for (i
= 0; i
< KD_BREAKPOINT_MAX
; i
++)
370 KdpBreakpointTable
[i
].Flags
= 0;
371 KdpBreakpointTable
[i
].DirectoryTableBase
= 0;
372 KdpBreakpointTable
[i
].Address
= NULL
;
375 /* Initialize the Time Slip DPC */
376 KeInitializeDpc(&KdpTimeSlipDpc
, KdpTimeSlipDpcRoutine
, NULL
);
377 KeInitializeTimer(&KdpTimeSlipTimer
);
378 ExInitializeWorkItem(&KdpTimeSlipWorkItem
, KdpTimeSlipWork
, NULL
);
380 /* First-time initialization done! */
381 KdpDebuggerStructuresInitialized
= TRUE
;
384 /* Initialize the timer */
385 KdTimerStart
.QuadPart
= 0;
387 /* Officially enable KD */
388 KdPitchDebugger
= FALSE
;
389 KdDebuggerEnabled
= TRUE
;
391 /* Let user-mode know that it's enabled as well */
392 SharedUserData
->KdDebuggerEnabled
= TRUE
;
394 /* Display separator + ReactOS version at start of the debug log */
395 MemSizeMBs
= KdpGetMemorySizeInMBs(KeLoaderBlock
);
396 KdpPrintBanner(MemSizeMBs
);
398 /* Check if the debugger should be disabled initially */
399 if (DisableKdAfterInit
)
402 KdDisableDebuggerWithLock(FALSE
);
405 * Save the enable block state and return initialized
406 * (the debugger is active but disabled).
408 KdBlockEnable
= BlockEnable
;
412 /* Check if we have a loader block */
415 /* Loop boot images */
416 NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
418 while ((NextEntry
!= &LoaderBlock
->LoadOrderListHead
) && (i
< 2))
420 /* Get the image entry */
421 LdrEntry
= CONTAINING_RECORD(NextEntry
,
422 LDR_DATA_TABLE_ENTRY
,
425 /* Generate the image name */
426 Name
= LdrEntry
->FullDllName
.Buffer
;
427 Length
= LdrEntry
->FullDllName
.Length
/ sizeof(WCHAR
);
431 /* Do cheap Unicode to ANSI conversion */
432 NameBuffer
[j
++] = (CHAR
)*Name
++;
433 } while (j
< Length
);
436 NameBuffer
[j
] = ANSI_NULL
;
438 /* Load symbols for image */
439 RtlInitString(&ImageName
, NameBuffer
);
440 DbgLoadImageSymbols(&ImageName
,
442 (ULONG_PTR
)PsGetCurrentProcessId());
444 /* Go to the next entry */
445 NextEntry
= NextEntry
->Flink
;
450 /* Check for incoming breakin and break on symbol load if we have it */
451 KdBreakAfterSymbolLoad
= KdPollBreakIn();
455 /* Disable debugger */
456 KdDebuggerNotPresent
= TRUE
;
459 /* Return initialized */