bafc17b5ba265ea993bef652a7b328a0647a1fa3
[reactos.git] / reactos / 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 <internal/debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 #define BufferSize 32*1024
18
19 HANDLE KdbLogFileHandle;
20 BOOLEAN KdpLogInitialized;
21 CHAR DebugBuffer[BufferSize];
22 ULONG CurrentPosition;
23 WORK_QUEUE_ITEM KdpDebugLogQueue;
24 BOOLEAN ItemQueued;
25 KD_PORT_INFORMATION SerialPortInfo = {DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0};
26
27 /* Current Port in use. FIXME: Do we support more then one? */
28 ULONG KdpPort;
29
30 /* DEBUG LOG FUNCTIONS *******************************************************/
31
32 VOID
33 STDCALL
34 KdpPrintToLogInternal(PVOID Context)
35 {
36 IO_STATUS_BLOCK Iosb;
37
38 /* Write to the Debug Log */
39 NtWriteFile(KdbLogFileHandle,
40 NULL,
41 NULL,
42 NULL,
43 &Iosb,
44 DebugBuffer,
45 CurrentPosition,
46 NULL,
47 NULL);
48
49 /* Clear the Current Position */
50 CurrentPosition = 0;
51
52 /* A new item can be queued now */
53 ItemQueued = FALSE;
54 }
55
56 VOID
57 STDCALL
58 KdpPrintToLog(PCH String,
59 ULONG StringLength)
60 {
61 /* Don't overflow */
62 if ((CurrentPosition + StringLength) > BufferSize) return;
63
64 /* Add the string to the buffer */
65 RtlMoveMemory(&DebugBuffer[CurrentPosition], String, StringLength);
66
67 /* Update the Current Position */
68 CurrentPosition += StringLength;
69
70 /* Make sure we are initialized and can queue */
71 if (!KdpLogInitialized || (ItemQueued)) return;
72
73 /*
74 * Queue the work item
75 * Note that we don't want to queue if we are > DISPATCH_LEVEL...
76 * The message is in the buffer and will simply be taken care of at
77 * the next time we are at <= DISPATCH, so it won't be lost.
78 */
79 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
80 {
81 ExQueueWorkItem(&KdpDebugLogQueue, HyperCriticalWorkQueue);
82 ItemQueued = TRUE;
83 }
84 }
85
86 VOID
87 STDCALL
88 KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
89 ULONG BootPhase)
90 {
91 NTSTATUS Status;
92 OBJECT_ATTRIBUTES ObjectAttributes;
93 UNICODE_STRING FileName;
94 IO_STATUS_BLOCK Iosb;
95
96 if (!KdpDebugMode.File) return;
97
98 if (BootPhase == 0)
99 {
100 /* Write out the functions that we support for now */
101 DispatchTable->KdpInitRoutine = KdpInitDebugLog;
102 DispatchTable->KdpPrintRoutine = KdpPrintToLog;
103
104 /* Register as a Provider */
105 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
106 }
107 else if (BootPhase == 2)
108 {
109 HalDisplayString("\n File log debugging enabled\n\n");
110 }
111 else if (BootPhase == 3)
112 {
113 /* Setup the Log Name */
114 RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log");
115 InitializeObjectAttributes(&ObjectAttributes,
116 &FileName,
117 0,
118 NULL,
119 NULL);
120
121 /* Create the Log File */
122 Status = NtCreateFile(&KdbLogFileHandle,
123 FILE_ALL_ACCESS,
124 &ObjectAttributes,
125 &Iosb,
126 NULL,
127 FILE_ATTRIBUTE_NORMAL,
128 FILE_SHARE_READ,
129 FILE_SUPERSEDE,
130 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
131 NULL,
132 0);
133
134 /* Allow it to be used */
135 ExInitializeWorkItem(&KdpDebugLogQueue, &KdpPrintToLogInternal, NULL);
136 KdpLogInitialized = TRUE;
137 }
138 }
139
140 /* SERIAL FUNCTIONS **********************************************************/
141
142 VOID
143 STDCALL
144 KdpSerialDebugPrint(LPSTR Message,
145 ULONG Length)
146 {
147 PCHAR pch = (PCHAR) Message;
148
149 while (*pch != 0)
150 {
151 if (*pch == '\n')
152 {
153 KdPortPutByteEx(&SerialPortInfo, '\r');
154 }
155 KdPortPutByteEx(&SerialPortInfo, *pch);
156 pch++;
157 }
158 }
159
160 VOID
161 STDCALL
162 KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
163 ULONG BootPhase)
164 {
165 if (!KdpDebugMode.Serial) return;
166
167 if (BootPhase == 0)
168 {
169 /* Write out the functions that we support for now */
170 DispatchTable->KdpInitRoutine = KdpSerialInit;
171 DispatchTable->KdpPrintRoutine = KdpSerialDebugPrint;
172
173 /* Initialize the Port */
174 if (!KdPortInitializeEx(&SerialPortInfo, 0, 0))
175 {
176 KdpDebugMode.Serial = FALSE;
177 return;
178 }
179
180 /* Register as a Provider */
181 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
182 }
183 else if (BootPhase == 2)
184 {
185 HalDisplayString("\n Serial debugging enabled\n\n");
186 }
187 }
188
189 /* SCREEN FUNCTIONS **********************************************************/
190
191 VOID
192 STDCALL
193 KdpScreenPrint(LPSTR Message,
194 ULONG Length)
195 {
196 /* Call HAL */
197 HalDisplayString(Message);
198 }
199
200 VOID
201 STDCALL
202 KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
203 ULONG BootPhase)
204 {
205 if (!KdpDebugMode.Screen) return;
206
207 if (BootPhase == 0)
208 {
209 /* Write out the functions that we support for now */
210 DispatchTable->KdpInitRoutine = KdpScreenInit;
211 DispatchTable->KdpPrintRoutine = KdpScreenPrint;
212
213 /* Register as a Provider */
214 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
215 }
216 else if (BootPhase == 2)
217 {
218 HalDisplayString("\n Screen debugging enabled\n\n");
219 }
220 }
221
222 /* GENERAL FUNCTIONS *********************************************************/
223
224 BOOLEAN
225 STDCALL
226 KdpDetectConflicts(PCM_RESOURCE_LIST DriverList)
227 {
228 ULONG ComPortBase = 0;
229 ULONG i;
230 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
231
232 /* Select the COM Port Base */
233 switch (KdpPort)
234 {
235 case 1: ComPortBase = 0x3f8; break;
236 case 2: ComPortBase = 0x2f8; break;
237 case 3: ComPortBase = 0x3e8; break;
238 case 4: ComPortBase = 0x2e8; break;
239 }
240
241 /* search for this port address in DriverList */
242 for (i = 0; i < DriverList->List[0].PartialResourceList.Count; i++)
243 {
244 ResourceDescriptor = &DriverList->List[0].PartialResourceList.PartialDescriptors[i];
245 if (ResourceDescriptor->Type == CmResourceTypePort)
246 {
247 if ((ResourceDescriptor->u.Port.Start.u.LowPart <= ComPortBase) &&
248 (ResourceDescriptor->u.Port.Start.u.LowPart +
249 ResourceDescriptor->u.Port.Length > ComPortBase))
250 {
251 /* Conflict found */
252 return TRUE;
253 }
254 }
255 }
256
257 /* No Conflicts */
258 return FALSE;
259 }
260
261 ULONG
262 STDCALL
263 KdpPrintString(LPSTR String,
264 ULONG Length)
265 {
266 if (!KdpDebugMode.Value) return 0;
267 PLIST_ENTRY CurrentEntry;
268 PKD_DISPATCH_TABLE CurrentTable;
269
270 /* Call the registered handlers */
271 CurrentEntry = KdProviders.Flink;
272 while (CurrentEntry != &KdProviders)
273 {
274 /* Get the current table */
275 CurrentTable = CONTAINING_RECORD(CurrentEntry,
276 KD_DISPATCH_TABLE,
277 KdProvidersList);
278
279 /* Call it */
280 CurrentTable->KdpPrintRoutine(String, Length);
281
282 /* Next Table */
283 CurrentEntry = CurrentEntry->Flink;
284 }
285
286 /* Call the Wrapper Routine */
287 if (WrapperInitRoutine) WrapperTable.KdpPrintRoutine(String, Length);
288
289 /* Return the Length */
290 return Length;
291 }
292
293 /* EOF */
294