- Add STATUS_SUCCESS to asm.h and make use of it.
[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 VOID
18 NTAPI
19 KdUpdateDataBlock(VOID)
20 {
21 /* Update the KeUserCallbackDispatcher pointer */
22 KdDebuggerDataBlock.KeUserCallbackDispatcher =
23 (ULONG_PTR)KeUserCallbackDispatcher;
24 }
25
26 BOOLEAN
27 NTAPI
28 KdRegisterDebuggerDataBlock(IN ULONG Tag,
29 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
30 IN ULONG Size)
31 {
32 KIRQL OldIrql;
33 PLIST_ENTRY NextEntry;
34 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader;
35
36 /* Acquire the Data Lock */
37 KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
38
39 /* Loop the debugger data list */
40 NextEntry = KdpDebuggerDataListHead.Flink;
41 while (NextEntry != &KdpDebuggerDataListHead)
42 {
43 /* Get the header for this entry */
44 CurrentHeader = CONTAINING_RECORD(NextEntry,
45 DBGKD_DEBUG_DATA_HEADER64,
46 List);
47
48 /* Move to the next one */
49 NextEntry = NextEntry->Flink;
50
51 /* Check if we already have this data block */
52 if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag))
53 {
54 /* Release the lock and fail */
55 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
56 return FALSE;
57 }
58 }
59
60 /* Setup the header */
61 DataHeader->OwnerTag = Tag;
62 DataHeader->Size = Size;
63
64 /* Insert it into the list and release the lock */
65 InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List);
66 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
67 return TRUE;
68 }
69
70 BOOLEAN
71 NTAPI
72 KdInitSystem(IN ULONG BootPhase,
73 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
74 {
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;
81 CHAR NameBuffer[256];
82 PWCHAR Name;
83
84 #if defined(__GNUC__)
85 /* Make gcc happy */
86 BlockEnable = FALSE;
87 #endif
88
89 /* Check if this is Phase 1 */
90 if (BootPhase)
91 {
92 /* Just query the performance counter */
93 KeQueryPerformanceCounter(&KdPerformanceCounterRate);
94 return TRUE;
95 }
96
97 /* Check if we already initialized once */
98 if (KdDebuggerEnabled) return TRUE;
99
100 /* Set the Debug Routine as the Stub for now */
101 KiDebugRoutine = KdpStub;
102
103 /* Disable break after symbol load for now */
104 KdBreakAfterSymbolLoad = FALSE;
105
106 /* Check if the Debugger Data Block was already initialized */
107 if (!KdpDebuggerDataListHead.Flink)
108 {
109 /* It wasn't...Initialize the KD Data Listhead */
110 InitializeListHead(&KdpDebuggerDataListHead);
111
112 /* Register the Debugger Data Block */
113 KdRegisterDebuggerDataBlock(KDBG_TAG,
114 &KdDebuggerDataBlock.Header,
115 sizeof(KdDebuggerDataBlock));
116
117 /* Fill out the KD Version Block */
118 KdVersionBlock.MajorVersion = (USHORT)(NtBuildNumber >> 28);
119 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF);
120
121 #ifdef CONFIG_SMP
122 /* This is an MP Build */
123 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
124 #endif
125
126 /* Save Pointers to Loaded Module List and Debugger Data */
127 KdVersionBlock.PsLoadedModuleList = (ULONG64)(LONG_PTR)&PsLoadedModuleList;
128 KdVersionBlock.DebuggerDataList = (ULONG64)(LONG_PTR)&KdpDebuggerDataListHead;
129
130 /* Set protocol limits */
131 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange -
132 DbgKdMinimumStateChange;
133 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate -
134 DbgKdMinimumManipulate;
135 KdVersionBlock.Unused[0] = 0;
136
137 /* Link us in the KPCR */
138 KeGetPcr()->KdVersionBlock = &KdVersionBlock;
139 }
140
141 /* Check if we have a loader block */
142 if (LoaderBlock)
143 {
144 /* Get the image entry */
145 LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
146 LDR_DATA_TABLE_ENTRY,
147 InLoadOrderLinks);
148
149 /* Save the Kernel Base */
150 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
151 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)LdrEntry->DllBase;
152
153 /* Check if we have a command line */
154 CommandLine = LoaderBlock->LoadOptions;
155 if (CommandLine)
156 {
157 /* Upcase it */
158 _strupr(CommandLine);
159
160 /* Assume we'll disable KD */
161 EnableKd = FALSE;
162
163 /* Check for CRASHDEBUG and NODEBUG */
164 if (strstr(CommandLine, "CRASHDEBUG")) KdPitchDebugger = FALSE;
165 if (strstr(CommandLine, "NODEBUG")) KdPitchDebugger = TRUE;
166
167 /* Check if DEBUG was on */
168 DebugLine = strstr(CommandLine, "DEBUG");
169 if (DebugLine)
170 {
171 /* Enable KD */
172 EnableKd = TRUE;
173
174 /* Check if there are any options */
175 if (DebugLine[5] == '=')
176 {
177 /* Save pointers */
178 DebugOptionStart = DebugOptionEnd = &DebugLine[6];
179
180 /* Scan the string for debug options */
181 for (;;)
182 {
183 /* Loop until we reach the end of the string */
184 while (*DebugOptionEnd != ANSI_NULL)
185 {
186 /* Check if this is a comma, a space or a tab */
187 if ((*DebugOptionEnd == ',') ||
188 (*DebugOptionEnd == ' ') ||
189 (*DebugOptionEnd == ' '))
190 {
191 /*
192 * We reached the end of the option or
193 * the end of the string, break out
194 */
195 break;
196 }
197 else
198 {
199 /* Move on to the next character */
200 DebugOptionEnd++;
201 }
202 }
203
204 /* Calculate the length of the current option */
205 DebugOptionLength = ((ULONG_PTR)DebugOptionEnd -
206 (ULONG_PTR)DebugOptionStart);
207
208 /*
209 * Break out if we reached the last option
210 * or if there were no options at all
211 */
212 if (!DebugOptionLength) break;
213
214 /* Now check which option this is */
215 if ((DebugOptionLength == 10) &&
216 !(strncmp(DebugOptionStart, "AUTOENABLE", 10)))
217 {
218 /*
219 * Disable the debugger, but
220 * allow it to be reenabled
221 */
222 DisableKdAfterInit = TRUE;
223 BlockEnable = FALSE;
224 KdAutoEnableOnEvent = TRUE;
225 }
226 else if ((DebugOptionLength == 7) &&
227 !(strncmp(DebugOptionStart, "DISABLE", 7)))
228 {
229 /* Disable the debugger */
230 DisableKdAfterInit = TRUE;
231 BlockEnable = TRUE;
232 KdAutoEnableOnEvent = FALSE;
233 }
234 else if ((DebugOptionLength == 6) &&
235 !(strncmp(DebugOptionStart, "NOUMEX", 6)))
236 {
237 /* Ignore user mode exceptions */
238 KdIgnoreUmExceptions = TRUE;
239 }
240
241 /*
242 * If there are more options then
243 * the next character should be a comma
244 */
245 if (*DebugOptionEnd != ',')
246 {
247 /* It isn't, break out */
248 break;
249 }
250
251 /* Move on to the next option */
252 DebugOptionEnd++;
253 DebugOptionStart = DebugOptionEnd;
254 }
255 }
256 }
257 }
258 else
259 {
260 /* No command line options? Disable debugger by default */
261 KdPitchDebugger = TRUE;
262 EnableKd = FALSE;
263 }
264 }
265 else
266 {
267 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
268 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)PsNtosImageBase;
269
270 /* Unconditionally enable KD */
271 EnableKd = TRUE;
272 }
273
274 /* Set the Kernel Base in the Data Block */
275 KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase;
276
277 /* Initialize the debugger if requested */
278 if ((EnableKd) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
279 {
280 /* Now set our real KD routine */
281 KiDebugRoutine = KdpTrap;
282
283 /* Check if we've already initialized our structures */
284 if (!KdpDebuggerStructuresInitialized)
285 {
286 /* Set the Debug Switch Routine and Retries*/
287 KdpContext.KdpDefaultRetries = 20;
288 KiDebugSwitchRoutine = KdpSwitchProcessor;
289
290 /* Initialize the Time Slip DPC */
291 KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
292 KeInitializeTimer(&KdpTimeSlipTimer);
293 ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
294
295 /* First-time initialization done! */
296 KdpDebuggerStructuresInitialized = TRUE;
297 }
298
299 /* Initialize the timer */
300 KdTimerStart.QuadPart = 0;
301
302 /* Officially enable KD */
303 KdPitchDebugger = FALSE;
304 KdDebuggerEnabled = TRUE;
305
306 /* Let user-mode know that it's enabled as well */
307 #undef KdDebuggerEnabled
308 SharedUserData->KdDebuggerEnabled = TRUE;
309 #define KdDebuggerEnabled _KdDebuggerEnabled
310
311 /* Check if the debugger should be disabled initially */
312 if (DisableKdAfterInit)
313 {
314 /* Disable it */
315 KdDisableDebuggerWithLock(FALSE);
316
317 /*
318 * Save the enable block state and return initialized
319 * (the debugger is active but disabled).
320 */
321 KdBlockEnable = BlockEnable;
322 return TRUE;
323 }
324
325 /* Check if we have a loader block */
326 if (LoaderBlock)
327 {
328 /* Loop boot images */
329 NextEntry = LoaderBlock->LoadOrderListHead.Flink;
330 i = 0;
331 while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
332 {
333 /* Get the image entry */
334 LdrEntry = CONTAINING_RECORD(NextEntry,
335 LDR_DATA_TABLE_ENTRY,
336 InLoadOrderLinks);
337
338 /* Generate the image name */
339 Name = LdrEntry->FullDllName.Buffer;
340 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
341 j = 0;
342 do
343 {
344 /* Do cheap Unicode to ANSI conversion */
345 NameBuffer[j++] = (CHAR)*Name++;
346 } while (j < Length);
347
348 /* Null-terminate */
349 NameBuffer[j] = ANSI_NULL;
350
351 /* Load symbols for image */
352 RtlInitAnsiString(&ImageName, NameBuffer);
353 DbgLoadImageSymbols(&ImageName, LdrEntry->DllBase, -1);
354
355 /* Go to the next entry */
356 NextEntry = NextEntry->Flink;
357 i++;
358 }
359 }
360
361 /* Check for incoming breakin and break on symbol load if we have it*/
362 KdBreakAfterSymbolLoad = KdPollBreakIn();
363 }
364 else
365 {
366 /* Disable debugger */
367 KdDebuggerNotPresent = TRUE;
368 }
369
370 /* Return initialized */
371 return TRUE;
372 }