[CMAKE]
[reactos.git] / ntoskrnl / kd / kdio.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/kd/kdio.c
5 * PURPOSE: NT Kernel Debugger Input/Output Functions
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 #define KdpBufferSize (1024 * 512)
18 BOOLEAN KdpLoggingEnabled = FALSE;
19 PCHAR KdpDebugBuffer = NULL;
20 volatile ULONG KdpCurrentPosition = 0;
21 volatile ULONG KdpFreeBytes = 0;
22 KSPIN_LOCK KdpDebugLogSpinLock;
23 KEVENT KdpLoggerThreadEvent;
24 HANDLE KdpLogFileHandle;
25
26 KSPIN_LOCK KdpSerialSpinLock;
27 KD_PORT_INFORMATION SerialPortInfo = { DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0 };
28
29 /* Current Port in use. FIXME: Do we support more then one? */
30 ULONG KdpPort;
31
32 /* DEBUG LOG FUNCTIONS *******************************************************/
33
34 VOID
35 NTAPI
36 KdpLoggerThread(PVOID Context)
37 {
38 ULONG beg, end, num;
39 IO_STATUS_BLOCK Iosb;
40
41 KdpLoggingEnabled = TRUE;
42
43 while (TRUE)
44 {
45 KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
46
47 /* Bug */
48 end = KdpCurrentPosition;
49 num = KdpFreeBytes;
50 beg = (end + num) % KdpBufferSize;
51 num = KdpBufferSize - num;
52
53 /* Nothing to do? */
54 if (num == 0)
55 continue;
56
57 if (end > beg)
58 {
59 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
60 KdpDebugBuffer + beg, num, NULL, NULL);
61 }
62 else
63 {
64 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
65 KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL);
66
67 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
68 KdpDebugBuffer, end, NULL, NULL);
69 }
70
71 (VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num);
72 }
73 }
74
75 VOID
76 NTAPI
77 KdpPrintToLogFile(PCH String,
78 ULONG StringLength)
79 {
80 ULONG beg, end, num;
81 KIRQL OldIrql;
82
83 if (KdpDebugBuffer == NULL) return;
84
85 /* Acquire the printing spinlock without waiting at raised IRQL */
86 while (TRUE)
87 {
88 /* Wait when the spinlock becomes available */
89 while (!KeTestSpinLock(&KdpDebugLogSpinLock));
90
91 /* Spinlock was free, raise IRQL */
92 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
93
94 /* Try to get the spinlock */
95 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDebugLogSpinLock))
96 break;
97
98 /* Someone else got the spinlock, lower IRQL back */
99 KeLowerIrql(OldIrql);
100 }
101
102 beg = KdpCurrentPosition;
103 num = KdpFreeBytes;
104 if (StringLength < num)
105 num = StringLength;
106
107 if (num != 0)
108 {
109 end = (beg + num) % KdpBufferSize;
110 KdpCurrentPosition = end;
111 KdpFreeBytes -= num;
112
113 if (end > beg)
114 {
115 RtlCopyMemory(KdpDebugBuffer + beg, String, num);
116 }
117 else
118 {
119 RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg);
120 RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end);
121 }
122 }
123
124 /* Release spinlock */
125 KiReleaseSpinLock(&KdpDebugLogSpinLock);
126
127 /* Lower IRQL */
128 KeLowerIrql(OldIrql);
129
130 /* Signal the logger thread */
131 if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled)
132 KeSetEvent(&KdpLoggerThreadEvent, 0, FALSE);
133 }
134
135 VOID
136 NTAPI
137 INIT_FUNCTION
138 KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
139 ULONG BootPhase)
140 {
141 NTSTATUS Status;
142 UNICODE_STRING FileName;
143 OBJECT_ATTRIBUTES ObjectAttributes;
144 IO_STATUS_BLOCK Iosb;
145 HANDLE ThreadHandle;
146 KPRIORITY Priority;
147
148 if (!KdpDebugMode.File) return;
149
150 if (BootPhase == 0)
151 {
152 KdComPortInUse = NULL;
153
154 /* Write out the functions that we support for now */
155 DispatchTable->KdpInitRoutine = KdpInitDebugLog;
156 DispatchTable->KdpPrintRoutine = KdpPrintToLogFile;
157
158 /* Register as a Provider */
159 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
160
161 }
162 else if (BootPhase == 1)
163 {
164 /* Allocate a buffer for debug log */
165 KdpDebugBuffer = ExAllocatePool(NonPagedPool, KdpBufferSize);
166 KdpFreeBytes = KdpBufferSize;
167
168 /* Initialize spinlock */
169 KeInitializeSpinLock(&KdpDebugLogSpinLock);
170
171 /* Display separator + ReactOS version at start of the debug log */
172 DPRINT1("---------------------------------------------------------------\n");
173 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
174 }
175 else if (BootPhase == 2)
176 {
177 HalDisplayString("\n File log debugging enabled\n\n");
178 }
179 else if (BootPhase == 3)
180 {
181 /* Setup the log name */
182 RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log");
183 InitializeObjectAttributes(&ObjectAttributes,
184 &FileName,
185 0,
186 NULL,
187 NULL);
188
189 /* Create the log file */
190 Status = NtCreateFile(&KdpLogFileHandle,
191 FILE_APPEND_DATA | SYNCHRONIZE,
192 &ObjectAttributes,
193 &Iosb,
194 NULL,
195 FILE_ATTRIBUTE_NORMAL,
196 FILE_SHARE_READ,
197 FILE_SUPERSEDE,
198 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
199 NULL,
200 0);
201
202 if (!NT_SUCCESS(Status)) return;
203
204 KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE);
205
206 /* Create the logger thread */
207 Status = PsCreateSystemThread(&ThreadHandle,
208 THREAD_ALL_ACCESS,
209 NULL,
210 NULL,
211 NULL,
212 KdpLoggerThread,
213 NULL);
214
215 if (!NT_SUCCESS(Status)) return;
216
217 Priority = 7;
218 NtSetInformationThread(ThreadHandle,
219 ThreadPriority,
220 &Priority,
221 sizeof(Priority));
222 }
223 }
224
225 /* SERIAL FUNCTIONS **********************************************************/
226
227 VOID
228 NTAPI
229 KdpSerialDebugPrint(LPSTR Message,
230 ULONG Length)
231 {
232 KIRQL OldIrql;
233 PCHAR pch = (PCHAR) Message;
234
235 /* Acquire the printing spinlock without waiting at raised IRQL */
236 while (TRUE)
237 {
238 /* Wait when the spinlock becomes available */
239 while (!KeTestSpinLock(&KdpSerialSpinLock));
240
241 /* Spinlock was free, raise IRQL */
242 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
243
244 /* Try to get the spinlock */
245 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpSerialSpinLock))
246 break;
247
248 /* Someone else got the spinlock, lower IRQL back */
249 KeLowerIrql(OldIrql);
250 }
251
252 /* Output the message */
253 while (*pch != 0)
254 {
255 if (*pch == '\n')
256 {
257 KdPortPutByteEx(&SerialPortInfo, '\r');
258 }
259 KdPortPutByteEx(&SerialPortInfo, *pch);
260 pch++;
261 }
262
263 /* Release spinlock */
264 KiReleaseSpinLock(&KdpSerialSpinLock);
265
266 /* Lower IRQL */
267 KeLowerIrql(OldIrql);
268 }
269
270 VOID
271 NTAPI
272 KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
273 ULONG BootPhase)
274 {
275 if (!KdpDebugMode.Serial) return;
276
277 if (BootPhase == 0)
278 {
279 /* Write out the functions that we support for now */
280 DispatchTable->KdpInitRoutine = KdpSerialInit;
281 DispatchTable->KdpPrintRoutine = KdpSerialDebugPrint;
282
283 /* Initialize the Port */
284 if (!KdPortInitializeEx(&SerialPortInfo, 0, 0))
285 {
286 KdpDebugMode.Serial = FALSE;
287 return;
288 }
289 KdComPortInUse = (PUCHAR)(ULONG_PTR)SerialPortInfo.BaseAddress;
290
291 /* Initialize spinlock */
292 KeInitializeSpinLock(&KdpSerialSpinLock);
293
294 /* Register as a Provider */
295 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
296
297 /* Display separator + ReactOS version at start of the debug log */
298 DPRINT1("-----------------------------------------------------\n");
299 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
300 DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
301 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
302 KeLoaderBlock->NtHalPathName,
303 KeLoaderBlock->ArcHalDeviceName,
304 KeLoaderBlock->NtBootPathName);
305 }
306 else if (BootPhase == 2)
307 {
308 HalDisplayString("\n Serial debugging enabled\n\n");
309 }
310 }
311
312 /* SCREEN FUNCTIONS **********************************************************/
313
314 VOID
315 NTAPI
316 KdpScreenPrint(LPSTR Message,
317 ULONG Length)
318 {
319 /* Call HAL */
320 HalDisplayString(Message);
321 }
322
323 VOID
324 NTAPI
325 KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
326 ULONG BootPhase)
327 {
328 if (!KdpDebugMode.Screen) return;
329
330 if (BootPhase == 0)
331 {
332 /* Write out the functions that we support for now */
333 DispatchTable->KdpInitRoutine = KdpScreenInit;
334 DispatchTable->KdpPrintRoutine = KdpScreenPrint;
335
336 /* Register as a Provider */
337 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
338 }
339 else if (BootPhase == 2)
340 {
341 HalDisplayString("\n Screen debugging enabled\n\n");
342 }
343 }
344
345 /* GENERAL FUNCTIONS *********************************************************/
346
347 ULONG
348 NTAPI
349 KdpPrintString(LPSTR String,
350 ULONG Length)
351 {
352 PLIST_ENTRY CurrentEntry;
353 PKD_DISPATCH_TABLE CurrentTable;
354
355 if (!KdpDebugMode.Value) return 0;
356
357 /* Call the registered handlers */
358 CurrentEntry = KdProviders.Flink;
359 while (CurrentEntry != &KdProviders)
360 {
361 /* Get the current table */
362 CurrentTable = CONTAINING_RECORD(CurrentEntry,
363 KD_DISPATCH_TABLE,
364 KdProvidersList);
365
366 /* Call it */
367 CurrentTable->KdpPrintRoutine(String, Length);
368
369 /* Next Table */
370 CurrentEntry = CurrentEntry->Flink;
371 }
372
373 /* Call the Wrapper Routine */
374 if (WrapperTable.KdpPrintRoutine)
375 WrapperTable.KdpPrintRoutine(String, Length);
376
377 /* Return the Length */
378 return Length;
379 }
380
381 /* EOF */