- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / kd64 / kdinit.c
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 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 BOOLEAN
18 NTAPI
19 KdRegisterDebuggerDataBlock(IN ULONG Tag,
20 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
21 IN ULONG Size)
22 {
23 KIRQL OldIrql;
24 PLIST_ENTRY NextEntry;
25 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader;
26
27 /* Acquire the Data Lock */
28 KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
29
30 /* Loop the debugger data list */
31 NextEntry = KdpDebuggerDataListHead.Flink;
32 while (NextEntry != &KdpDebuggerDataListHead)
33 {
34 /* Get the header for this entry */
35 CurrentHeader = CONTAINING_RECORD(NextEntry,
36 DBGKD_DEBUG_DATA_HEADER64,
37 List);
38
39 /* Move to the next one */
40 NextEntry = NextEntry->Flink;
41
42 /* Check if we already have this data block */
43 if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag))
44 {
45 /* Release the lock and fail */
46 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
47 return FALSE;
48 }
49 }
50
51 /* Setup the header */
52 DataHeader->OwnerTag = Tag;
53 DataHeader->Size = Size;
54
55 /* Insert it into the list and release the lock */
56 InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List);
57 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
58 return TRUE;
59 }
60
61 BOOLEAN
62 NTAPI
63 KdInitSystem(IN ULONG BootPhase,
64 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
65 {
66 BOOLEAN EnableKd;
67 LPSTR CommandLine, DebugLine;
68 ANSI_STRING ImageName;
69 PLDR_DATA_TABLE_ENTRY LdrEntry;
70 PLIST_ENTRY NextEntry;
71 ULONG i;
72 CHAR NameBuffer[256];
73
74 /* Check if this is Phase 1 */
75 if (BootPhase)
76 {
77 /* Just query the performance counter */
78 KeQueryPerformanceCounter(&KdPerformanceCounterRate);
79 return TRUE;
80 }
81
82 /* Check if we already initialized once */
83 if (KdDebuggerEnabled) return TRUE;
84
85 /* Set the Debug Routine as the Stub for now */
86 KiDebugRoutine = KdpStub;
87
88 /* Disable break after symbol load for now */
89 KdBreakAfterSymbolLoad = FALSE;
90
91 /* Check if the Debugger Data Block was already initialized */
92 if (!KdpDebuggerDataListHead.Flink)
93 {
94 /* It wasn't...Initialize the KD Data Listhead */
95 InitializeListHead(&KdpDebuggerDataListHead);
96
97 /* Register the Debugger Data Block */
98 KdRegisterDebuggerDataBlock(KDBG_TAG,
99 &KdDebuggerDataBlock.Header,
100 sizeof(KdDebuggerDataBlock));
101
102 /* Fill out the KD Version Block */
103 KdVersionBlock.MajorVersion = (USHORT)(NtBuildNumber >> 28);
104 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF);
105
106 #ifdef CONFIG_SMP
107 /* This is an MP Build */
108 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
109 #endif
110
111 /* Save Pointers to Loaded Module List and Debugger Data */
112 KdVersionBlock.PsLoadedModuleList = (ULONG64)&PsLoadedModuleList;
113 KdVersionBlock.DebuggerDataList = (ULONG64)&KdpDebuggerDataListHead;
114
115 /* Set protocol limits */
116 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange -
117 DbgKdMinimumStateChange;
118 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate -
119 DbgKdMinimumManipulate;
120 KdVersionBlock.Unused[0] = 0;
121
122 /* Link us in the KPCR */
123 KeGetPcr()->KdVersionBlock = &KdVersionBlock;
124 }
125
126 /* Check if we have a loader block */
127 if (LoaderBlock)
128 {
129 /* Save the Kernel Base */
130 KdVersionBlock.KernBase = (ULONG64)LoaderBlock->KernelStack;
131
132 /* Check if we have a command line */
133 CommandLine = LoaderBlock->LoadOptions;
134 if (CommandLine)
135 {
136 /* Upcase it */
137 _strupr(CommandLine);
138
139 /* Assume we'll disable KD */
140 EnableKd = FALSE;
141
142 /* Check for CRASHDEBUG and NODEBUG */
143 if (strstr(CommandLine, "CRASHDEBUG")) KdPitchDebugger = FALSE;
144 if (strstr(CommandLine, "NODEBUG")) KdPitchDebugger = TRUE;
145
146 /* Check if DEBUG was on */
147 DebugLine = strstr(CommandLine, "DEBUG");
148 if (DebugLine)
149 {
150 /* Enable KD */
151 EnableKd = TRUE;
152
153 /* Check if there was additional data */
154 if (DebugLine[5] == '=')
155 {
156 /* FIXME: Check for NOUMEX, DISABLE, AUTOENABLE */
157 }
158 }
159 }
160 else
161 {
162 /* No command line options? Disable debugger by default */
163 KdPitchDebugger = TRUE;
164 EnableKd = FALSE;
165 }
166 }
167 else
168 {
169 /* Called from a bugcheck...Save the Kernel Base */
170 KdVersionBlock.KernBase = PsNtosImageBase;
171
172 /* Unconditionally enable KD */
173 EnableKd = TRUE;
174 }
175
176 /* Set the Kernel Base in the Data Block */
177 KdDebuggerDataBlock.KernBase = KdVersionBlock.KernBase;
178
179 /* Initialize the debugger if requested */
180 if ((EnableKd) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
181 {
182 /* Now set our real KD routine */
183 KiDebugRoutine = KdpTrap;
184
185 /* Check if we've already initialized our structures */
186 if (!KdpDebuggerStructuresInitialized)
187 {
188 /* Set the Debug Switch Routine and Retries*/
189 KdpContext.KdpDefaultRetries = 20;
190 KiDebugSwitchRoutine = KdpSwitchProcessor;
191
192 /* Initialize the Time Slip DPC */
193 KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
194 KeInitializeTimer(&KdpTimeSlipTimer);
195 ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
196
197 /* First-time initialization done! */
198 KdpDebuggerStructuresInitialized = TRUE;
199 }
200
201 /* Initialize the timer */
202 KdTimerStart.QuadPart = 0;
203
204 /* Officially enable KD */
205 KdPitchDebugger = FALSE;
206 KdDebuggerEnabled = TRUE;
207
208 /* Let user-mode know that it's enabled as well */
209 //#undef KdDebuggerEnabled
210 //SharedUserData->KdDebuggerEnabled = TRUE;
211 //#define KdDebuggerEnabled _KdDebuggerEnabled
212
213 /* Check if we have a loader block */
214 if (LoaderBlock)
215 {
216 /* Loop boot images */
217 NextEntry = LoaderBlock->LoadOrderListHead.Flink;
218 i = 0;
219 while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
220 {
221 /* Get the image entry */
222 LdrEntry = CONTAINING_RECORD(NextEntry,
223 LDR_DATA_TABLE_ENTRY,
224 InLoadOrderLinks);
225
226 /* Generate the image name */
227
228 /* Load symbols for image */
229 RtlInitAnsiString(&ImageName, NameBuffer);
230 DbgLoadImageSymbols(&ImageName, LdrEntry->DllBase, -1);
231
232 /* Go to the next entry */
233 NextEntry = NextEntry->Flink;
234 i++;
235 }
236 }
237
238 /* Check for incoming breakin and break on symbol load if we have it*/
239 KdBreakAfterSymbolLoad = KdPollBreakIn();
240 }
241 else
242 {
243 /* Disable debugger */
244 KdDebuggerNotPresent = TRUE;
245 }
246
247 /* Return initialized */
248 return TRUE;
249 }