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 return NumberOfPhysicalPages
* PAGE_SIZE
/ 1024 / 1024;
68 /* See also: kd\kdio.c */
71 KdpPrintBanner(IN SIZE_T MemSizeMBs
)
73 DPRINT1("-----------------------------------------------------\n");
74 DPRINT1("ReactOS " KERNEL_VERSION_STR
" (Build " KERNEL_VERSION_BUILD_STR
") (Commit " KERNEL_VERSION_COMMIT_HASH
")\n");
75 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors
, MemSizeMBs
);
79 DPRINT1("Command Line: %s\n", KeLoaderBlock
->LoadOptions
);
80 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock
->ArcBootDeviceName
, KeLoaderBlock
->NtHalPathName
, KeLoaderBlock
->ArcHalDeviceName
, KeLoaderBlock
->NtBootPathName
);
84 /* FUNCTIONS *****************************************************************/
88 KdUpdateDataBlock(VOID
)
90 /* Update the KeUserCallbackDispatcher pointer */
91 KdDebuggerDataBlock
.KeUserCallbackDispatcher
=
92 (ULONG_PTR
)KeUserCallbackDispatcher
;
97 KdRegisterDebuggerDataBlock(IN ULONG Tag
,
98 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader
,
102 PLIST_ENTRY NextEntry
;
103 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader
;
105 /* Acquire the Data Lock */
106 KeAcquireSpinLock(&KdpDataSpinLock
, &OldIrql
);
108 /* Loop the debugger data list */
109 NextEntry
= KdpDebuggerDataListHead
.Flink
;
110 while (NextEntry
!= &KdpDebuggerDataListHead
)
112 /* Get the header for this entry */
113 CurrentHeader
= CONTAINING_RECORD(NextEntry
,
114 DBGKD_DEBUG_DATA_HEADER64
,
117 /* Move to the next one */
118 NextEntry
= NextEntry
->Flink
;
120 /* Check if we already have this data block */
121 if ((CurrentHeader
== DataHeader
) || (CurrentHeader
->OwnerTag
== Tag
))
123 /* Release the lock and fail */
124 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
129 /* Setup the header */
130 DataHeader
->OwnerTag
= Tag
;
131 DataHeader
->Size
= Size
;
133 /* Insert it into the list and release the lock */
134 InsertTailList(&KdpDebuggerDataListHead
, (PLIST_ENTRY
)&DataHeader
->List
);
135 KeReleaseSpinLock(&KdpDataSpinLock
, OldIrql
);
141 KdInitSystem(IN ULONG BootPhase
,
142 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
144 BOOLEAN EnableKd
, DisableKdAfterInit
= FALSE
, BlockEnable
;
145 LPSTR CommandLine
, DebugLine
, DebugOptionStart
, DebugOptionEnd
;
147 PLDR_DATA_TABLE_ENTRY LdrEntry
;
148 PLIST_ENTRY NextEntry
;
150 SIZE_T DebugOptionLength
;
152 CHAR NameBuffer
[256];
155 #if defined(__GNUC__)
160 /* Check if this is Phase 1 */
163 /* Just query the performance counter */
164 KeQueryPerformanceCounter(&KdPerformanceCounterRate
);
168 /* Check if we already initialized once */
169 if (KdDebuggerEnabled
) return TRUE
;
171 /* Set the Debug Routine as the Stub for now */
172 KiDebugRoutine
= KdpStub
;
174 /* Disable break after symbol load for now */
175 KdBreakAfterSymbolLoad
= FALSE
;
177 /* Check if the Debugger Data Block was already initialized */
178 if (!KdpDebuggerDataListHead
.Flink
)
180 /* It wasn't...Initialize the KD Data Listhead */
181 InitializeListHead(&KdpDebuggerDataListHead
);
183 /* Register the Debugger Data Block */
184 KdRegisterDebuggerDataBlock(KDBG_TAG
,
185 &KdDebuggerDataBlock
.Header
,
186 sizeof(KdDebuggerDataBlock
));
188 /* Fill out the KD Version Block */
189 KdVersionBlock
.MajorVersion
= (USHORT
)((DBGKD_MAJOR_NT
<< 8) | (NtBuildNumber
>> 28));
190 KdVersionBlock
.MinorVersion
= (USHORT
)(NtBuildNumber
& 0xFFFF);
193 /* This is an MP Build */
194 KdVersionBlock
.Flags
|= DBGKD_VERS_FLAG_MP
;
197 /* Save Pointers to Loaded Module List and Debugger Data */
198 KdVersionBlock
.PsLoadedModuleList
= (ULONG64
)(LONG_PTR
)&PsLoadedModuleList
;
199 KdVersionBlock
.DebuggerDataList
= (ULONG64
)(LONG_PTR
)&KdpDebuggerDataListHead
;
201 /* Set protocol limits */
202 KdVersionBlock
.MaxStateChange
= DbgKdMaximumStateChange
-
203 DbgKdMinimumStateChange
;
204 KdVersionBlock
.MaxManipulate
= DbgKdMaximumManipulate
-
205 DbgKdMinimumManipulate
;
206 KdVersionBlock
.Unused
[0] = 0;
208 /* Link us in the KPCR */
209 KeGetPcr()->KdVersionBlock
= &KdVersionBlock
;
212 /* Check if we have a loader block */
215 /* Get the image entry */
216 LdrEntry
= CONTAINING_RECORD(LoaderBlock
->LoadOrderListHead
.Flink
,
217 LDR_DATA_TABLE_ENTRY
,
220 /* Save the Kernel Base */
221 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
222 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)LdrEntry
->DllBase
;
224 /* Check if we have a command line */
225 CommandLine
= LoaderBlock
->LoadOptions
;
229 _strupr(CommandLine
);
231 /* Assume we'll disable KD */
234 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
235 if (strstr(CommandLine
, "CRASHDEBUG"))
237 /* Don't enable KD now, but allow it to be enabled later */
238 KdPitchDebugger
= FALSE
;
240 else if (strstr(CommandLine
, "NODEBUG"))
242 /* Don't enable KD and don't let it be enabled later */
243 KdPitchDebugger
= TRUE
;
245 else if ((DebugLine
= strstr(CommandLine
, "DEBUG")) != NULL
)
250 /* Check if there are any options */
251 if (DebugLine
[5] == '=')
254 DebugOptionStart
= DebugOptionEnd
= &DebugLine
[6];
256 /* Scan the string for debug options */
259 /* Loop until we reach the end of the string */
260 while (*DebugOptionEnd
!= ANSI_NULL
)
262 /* Check if this is a comma, a space or a tab */
263 if ((*DebugOptionEnd
== ',') ||
264 (*DebugOptionEnd
== ' ') ||
265 (*DebugOptionEnd
== '\t'))
268 * We reached the end of the option or
269 * the end of the string, break out
275 /* Move on to the next character */
280 /* Calculate the length of the current option */
281 DebugOptionLength
= (DebugOptionEnd
- DebugOptionStart
);
284 * Break out if we reached the last option
285 * or if there were no options at all
287 if (!DebugOptionLength
) break;
289 /* Now check which option this is */
290 if ((DebugOptionLength
== 10) &&
291 !(strncmp(DebugOptionStart
, "AUTOENABLE", 10)))
294 * Disable the debugger, but
295 * allow it to be reenabled
297 DisableKdAfterInit
= TRUE
;
299 KdAutoEnableOnEvent
= TRUE
;
301 else if ((DebugOptionLength
== 7) &&
302 !(strncmp(DebugOptionStart
, "DISABLE", 7)))
304 /* Disable the debugger */
305 DisableKdAfterInit
= TRUE
;
307 KdAutoEnableOnEvent
= FALSE
;
309 else if ((DebugOptionLength
== 6) &&
310 !(strncmp(DebugOptionStart
, "NOUMEX", 6)))
312 /* Ignore user mode exceptions */
313 KdIgnoreUmExceptions
= TRUE
;
317 * If there are more options then
318 * the next character should be a comma
320 if (*DebugOptionEnd
!= ',')
322 /* It isn't, break out */
326 /* Move on to the next option */
328 DebugOptionStart
= DebugOptionEnd
;
335 /* No command line options? Disable debugger by default */
336 KdPitchDebugger
= TRUE
;
342 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
343 KdVersionBlock
.KernBase
= (ULONG64
)(LONG_PTR
)PsNtosImageBase
;
345 /* Unconditionally enable KD */
349 /* Set the Kernel Base in the Data Block */
350 KdDebuggerDataBlock
.KernBase
= (ULONG_PTR
)KdVersionBlock
.KernBase
;
352 /* Initialize the debugger if requested */
353 if (EnableKd
&& (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock
))))
355 /* Now set our real KD routine */
356 KiDebugRoutine
= KdpTrap
;
358 /* Check if we've already initialized our structures */
359 if (!KdpDebuggerStructuresInitialized
)
361 /* Set the Debug Switch Routine and Retries */
362 KdpContext
.KdpDefaultRetries
= 20;
363 KiDebugSwitchRoutine
= KdpSwitchProcessor
;
365 /* Initialize breakpoints owed flag and table */
366 KdpOweBreakpoint
= FALSE
;
367 for (i
= 0; i
< KD_BREAKPOINT_MAX
; i
++)
369 KdpBreakpointTable
[i
].Flags
= 0;
370 KdpBreakpointTable
[i
].DirectoryTableBase
= 0;
371 KdpBreakpointTable
[i
].Address
= NULL
;
374 /* Initialize the Time Slip DPC */
375 KeInitializeDpc(&KdpTimeSlipDpc
, KdpTimeSlipDpcRoutine
, NULL
);
376 KeInitializeTimer(&KdpTimeSlipTimer
);
377 ExInitializeWorkItem(&KdpTimeSlipWorkItem
, KdpTimeSlipWork
, NULL
);
379 /* First-time initialization done! */
380 KdpDebuggerStructuresInitialized
= TRUE
;
383 /* Initialize the timer */
384 KdTimerStart
.QuadPart
= 0;
386 /* Officially enable KD */
387 KdPitchDebugger
= FALSE
;
388 KdDebuggerEnabled
= TRUE
;
390 /* Let user-mode know that it's enabled as well */
391 SharedUserData
->KdDebuggerEnabled
= TRUE
;
393 /* Display separator + ReactOS version at start of the debug log */
394 MemSizeMBs
= KdpGetMemorySizeInMBs(KeLoaderBlock
);
395 KdpPrintBanner(MemSizeMBs
);
397 /* Check if the debugger should be disabled initially */
398 if (DisableKdAfterInit
)
401 KdDisableDebuggerWithLock(FALSE
);
404 * Save the enable block state and return initialized
405 * (the debugger is active but disabled).
407 KdBlockEnable
= BlockEnable
;
411 /* Check if we have a loader block */
414 /* Loop boot images */
415 NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
417 while ((NextEntry
!= &LoaderBlock
->LoadOrderListHead
) && (i
< 2))
419 /* Get the image entry */
420 LdrEntry
= CONTAINING_RECORD(NextEntry
,
421 LDR_DATA_TABLE_ENTRY
,
424 /* Generate the image name */
425 Name
= LdrEntry
->FullDllName
.Buffer
;
426 Length
= LdrEntry
->FullDllName
.Length
/ sizeof(WCHAR
);
430 /* Do cheap Unicode to ANSI conversion */
431 NameBuffer
[j
++] = (CHAR
)*Name
++;
432 } while (j
< Length
);
435 NameBuffer
[j
] = ANSI_NULL
;
437 /* Load symbols for image */
438 RtlInitString(&ImageName
, NameBuffer
);
439 DbgLoadImageSymbols(&ImageName
,
441 (ULONG_PTR
)PsGetCurrentProcessId());
443 /* Go to the next entry */
444 NextEntry
= NextEntry
->Flink
;
449 /* Check for incoming breakin and break on symbol load if we have it */
450 KdBreakAfterSymbolLoad
= KdPollBreakIn();
454 /* Disable debugger */
455 KdDebuggerNotPresent
= TRUE
;
458 /* Return initialized */