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