efd8e29a3215f3778136f3369ea9bad0535a2d71
[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 (ULONG64)(LONG_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;
76 LPSTR CommandLine, DebugLine;
77 ANSI_STRING ImageName;
78 PLDR_DATA_TABLE_ENTRY LdrEntry;
79 PLIST_ENTRY NextEntry;
80 ULONG i, j, Length;
81 CHAR NameBuffer[256];
82 PWCHAR Name;
83
84 /* Check if this is Phase 1 */
85 if (BootPhase)
86 {
87 /* Just query the performance counter */
88 KeQueryPerformanceCounter(&KdPerformanceCounterRate);
89 return TRUE;
90 }
91
92 /* Check if we already initialized once */
93 if (KdDebuggerEnabled) return TRUE;
94
95 /* Set the Debug Routine as the Stub for now */
96 KiDebugRoutine = KdpStub;
97
98 /* Disable break after symbol load for now */
99 KdBreakAfterSymbolLoad = FALSE;
100
101 /* Check if the Debugger Data Block was already initialized */
102 if (!KdpDebuggerDataListHead.Flink)
103 {
104 /* It wasn't...Initialize the KD Data Listhead */
105 InitializeListHead(&KdpDebuggerDataListHead);
106
107 /* Register the Debugger Data Block */
108 KdRegisterDebuggerDataBlock(KDBG_TAG,
109 &KdDebuggerDataBlock.Header,
110 sizeof(KdDebuggerDataBlock));
111
112 /* Fill out the KD Version Block */
113 KdVersionBlock.MajorVersion = (USHORT)(NtBuildNumber >> 28);
114 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF);
115
116 #ifdef CONFIG_SMP
117 /* This is an MP Build */
118 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
119 #endif
120
121 /* Save Pointers to Loaded Module List and Debugger Data */
122 KdVersionBlock.PsLoadedModuleList = (ULONGLONG)(LONG_PTR)&PsLoadedModuleList;
123 KdVersionBlock.DebuggerDataList = (ULONGLONG)(LONG_PTR)&KdpDebuggerDataListHead;
124
125 /* Set protocol limits */
126 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange -
127 DbgKdMinimumStateChange;
128 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate -
129 DbgKdMinimumManipulate;
130 KdVersionBlock.Unused[0] = 0;
131
132 /* Link us in the KPCR */
133 KeGetPcr()->KdVersionBlock = &KdVersionBlock;
134 }
135
136 /* Check if we have a loader block */
137 if (LoaderBlock)
138 {
139 /* Get the image entry */
140 LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
141 LDR_DATA_TABLE_ENTRY,
142 InLoadOrderLinks);
143
144 /* Save the Kernel Base */
145 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
146 KdVersionBlock.KernBase = (ULONGLONG)(LONG_PTR)LdrEntry->DllBase;
147
148 /* Check if we have a command line */
149 CommandLine = LoaderBlock->LoadOptions;
150 if (CommandLine)
151 {
152 /* Upcase it */
153 _strupr(CommandLine);
154
155 /* Assume we'll disable KD */
156 EnableKd = FALSE;
157
158 /* Check for CRASHDEBUG and NODEBUG */
159 if (strstr(CommandLine, "CRASHDEBUG")) KdPitchDebugger = FALSE;
160 if (strstr(CommandLine, "NODEBUG")) KdPitchDebugger = TRUE;
161
162 /* Check if DEBUG was on */
163 DebugLine = strstr(CommandLine, "DEBUG");
164 if (DebugLine)
165 {
166 /* Enable KD */
167 EnableKd = TRUE;
168
169 /* Check if there was additional data */
170 if (DebugLine[5] == '=')
171 {
172 /* FIXME: Check for NOUMEX, DISABLE, AUTOENABLE */
173 }
174 }
175 }
176 else
177 {
178 /* No command line options? Disable debugger by default */
179 KdPitchDebugger = TRUE;
180 EnableKd = FALSE;
181 }
182 }
183 else
184 {
185 /* Called from a bugcheck...Save the Kernel Base */
186 KdVersionBlock.KernBase = (ULONGLONG)(LONG_PTR)PsNtosImageBase;
187
188 /* Unconditionally enable KD */
189 EnableKd = TRUE;
190 }
191
192 /* Set the Kernel Base in the Data Block */
193 KdDebuggerDataBlock.KernBase = (ULONGLONG)(LONG_PTR)KdVersionBlock.KernBase;
194
195 /* Initialize the debugger if requested */
196 if ((EnableKd) && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
197 {
198 /* Now set our real KD routine */
199 KiDebugRoutine = KdpTrap;
200
201 /* Check if we've already initialized our structures */
202 if (!KdpDebuggerStructuresInitialized)
203 {
204 /* Set the Debug Switch Routine and Retries*/
205 KdpContext.KdpDefaultRetries = 20;
206 KiDebugSwitchRoutine = KdpSwitchProcessor;
207
208 /* Initialize the Time Slip DPC */
209 KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
210 KeInitializeTimer(&KdpTimeSlipTimer);
211 ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
212
213 /* First-time initialization done! */
214 KdpDebuggerStructuresInitialized = TRUE;
215 }
216
217 /* Initialize the timer */
218 KdTimerStart.QuadPart = 0;
219
220 /* Officially enable KD */
221 KdPitchDebugger = FALSE;
222 KdDebuggerEnabled = TRUE;
223
224 /* Let user-mode know that it's enabled as well */
225 #undef KdDebuggerEnabled
226 SharedUserData->KdDebuggerEnabled = TRUE;
227 #define KdDebuggerEnabled _KdDebuggerEnabled
228
229 /* Check if we have a loader block */
230 if (LoaderBlock)
231 {
232 /* Loop boot images */
233 NextEntry = LoaderBlock->LoadOrderListHead.Flink;
234 i = 0;
235 while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
236 {
237 /* Get the image entry */
238 LdrEntry = CONTAINING_RECORD(NextEntry,
239 LDR_DATA_TABLE_ENTRY,
240 InLoadOrderLinks);
241
242 /* Generate the image name */
243 Name = LdrEntry->FullDllName.Buffer;
244 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
245 j = 0;
246 do
247 {
248 /* Do cheap Unicode to ANSI conversion */
249 NameBuffer[j++] = (CHAR)*Name++;
250 } while (j < Length);
251
252 /* Null-terminate */
253 NameBuffer[j] = ANSI_NULL;
254
255 /* Load symbols for image */
256 RtlInitAnsiString(&ImageName, NameBuffer);
257 DbgLoadImageSymbols(&ImageName, LdrEntry->DllBase, -1);
258
259 /* Go to the next entry */
260 NextEntry = NextEntry->Flink;
261 i++;
262 }
263 }
264
265 /* Check for incoming breakin and break on symbol load if we have it*/
266 KdBreakAfterSymbolLoad = KdPollBreakIn();
267 }
268 else
269 {
270 /* Disable debugger */
271 KdDebuggerNotPresent = TRUE;
272 }
273
274 /* Return initialized */
275 return TRUE;
276 }