Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkdio.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/kd/kdio.c 00005 * PURPOSE: NT Kernel Debugger Input/Output Functions 00006 * 00007 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #include <reactos/buildno.h> 00014 #include <debug.h> 00015 00016 /* GLOBALS *******************************************************************/ 00017 00018 #define KdpBufferSize (1024 * 512) 00019 BOOLEAN KdpLoggingEnabled = FALSE; 00020 PCHAR KdpDebugBuffer = NULL; 00021 volatile ULONG KdpCurrentPosition = 0; 00022 volatile ULONG KdpFreeBytes = 0; 00023 KSPIN_LOCK KdpDebugLogSpinLock; 00024 KEVENT KdpLoggerThreadEvent; 00025 HANDLE KdpLogFileHandle; 00026 ANSI_STRING KdpLogFileName = RTL_CONSTANT_STRING("\\SystemRoot\\debug.log"); 00027 00028 KSPIN_LOCK KdpSerialSpinLock; 00029 KD_PORT_INFORMATION SerialPortInfo = { DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0 }; 00030 00031 /* Current Port in use. FIXME: Do we support more then one? */ 00032 ULONG KdpPort; 00033 00034 #define KdpScreenLineLenght 80 00035 CHAR KdpScreenLineBuffer[KdpScreenLineLenght + 1] = ""; 00036 ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0; 00037 00038 const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024; 00039 PCHAR KdpDmesgBuffer = NULL; 00040 volatile ULONG KdpDmesgCurrentPosition = 0; 00041 volatile ULONG KdpDmesgFreeBytes = 0; 00042 volatile ULONG KdbDmesgTotalWritten = 0; 00043 KSPIN_LOCK KdpDmesgLogSpinLock; 00044 volatile BOOLEAN KdbpIsInDmesgMode = FALSE; 00045 00046 /* FILE DEBUG LOG FUNCTIONS **************************************************/ 00047 00048 VOID 00049 NTAPI 00050 KdpLoggerThread(PVOID Context) 00051 { 00052 ULONG beg, end, num; 00053 IO_STATUS_BLOCK Iosb; 00054 00055 KdpLoggingEnabled = TRUE; 00056 00057 while (TRUE) 00058 { 00059 KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL); 00060 00061 /* Bug */ 00062 /* Keep KdpCurrentPosition and KdpFreeBytes values in local 00063 * variables to avoid their possible change from Producer part, 00064 * KdpPrintToLogFile function 00065 */ 00066 end = KdpCurrentPosition; 00067 num = KdpFreeBytes; 00068 00069 /* Now securely calculate values, based on local variables */ 00070 beg = (end + num) % KdpBufferSize; 00071 num = KdpBufferSize - num; 00072 00073 /* Nothing to do? */ 00074 if (num == 0) 00075 continue; 00076 00077 if (end > beg) 00078 { 00079 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 00080 KdpDebugBuffer + beg, num, NULL, NULL); 00081 } 00082 else 00083 { 00084 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 00085 KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL); 00086 00087 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 00088 KdpDebugBuffer, end, NULL, NULL); 00089 } 00090 00091 (VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num); 00092 } 00093 } 00094 00095 VOID 00096 NTAPI 00097 KdpPrintToLogFile(PCH String, 00098 ULONG StringLength) 00099 { 00100 ULONG beg, end, num; 00101 KIRQL OldIrql; 00102 00103 if (KdpDebugBuffer == NULL) return; 00104 00105 /* Acquire the printing spinlock without waiting at raised IRQL */ 00106 while (TRUE) 00107 { 00108 /* Wait when the spinlock becomes available */ 00109 while (!KeTestSpinLock(&KdpDebugLogSpinLock)); 00110 00111 /* Spinlock was free, raise IRQL */ 00112 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 00113 00114 /* Try to get the spinlock */ 00115 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDebugLogSpinLock)) 00116 break; 00117 00118 /* Someone else got the spinlock, lower IRQL back */ 00119 KeLowerIrql(OldIrql); 00120 } 00121 00122 beg = KdpCurrentPosition; 00123 num = KdpFreeBytes; 00124 if (StringLength < num) 00125 num = StringLength; 00126 00127 if (num != 0) 00128 { 00129 end = (beg + num) % KdpBufferSize; 00130 KdpCurrentPosition = end; 00131 KdpFreeBytes -= num; 00132 00133 if (end > beg) 00134 { 00135 RtlCopyMemory(KdpDebugBuffer + beg, String, num); 00136 } 00137 else 00138 { 00139 RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg); 00140 RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end); 00141 } 00142 } 00143 00144 /* Release spinlock */ 00145 KiReleaseSpinLock(&KdpDebugLogSpinLock); 00146 00147 /* Lower IRQL */ 00148 KeLowerIrql(OldIrql); 00149 00150 /* Signal the logger thread */ 00151 if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled) 00152 KeSetEvent(&KdpLoggerThreadEvent, 0, FALSE); 00153 } 00154 00155 VOID 00156 NTAPI 00157 INIT_FUNCTION 00158 KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable, 00159 ULONG BootPhase) 00160 { 00161 NTSTATUS Status; 00162 UNICODE_STRING FileName; 00163 OBJECT_ATTRIBUTES ObjectAttributes; 00164 IO_STATUS_BLOCK Iosb; 00165 HANDLE ThreadHandle; 00166 KPRIORITY Priority; 00167 SIZE_T MemSizeMBs; 00168 00169 if (!KdpDebugMode.File) return; 00170 00171 if (BootPhase == 0) 00172 { 00173 KdComPortInUse = NULL; 00174 00175 /* Write out the functions that we support for now */ 00176 DispatchTable->KdpInitRoutine = KdpInitDebugLog; 00177 DispatchTable->KdpPrintRoutine = KdpPrintToLogFile; 00178 00179 /* Register as a Provider */ 00180 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 00181 00182 } 00183 else if (BootPhase == 1) 00184 { 00185 /* Allocate a buffer for debug log */ 00186 KdpDebugBuffer = ExAllocatePool(NonPagedPool, KdpBufferSize); 00187 KdpFreeBytes = KdpBufferSize; 00188 00189 /* Initialize spinlock */ 00190 KeInitializeSpinLock(&KdpDebugLogSpinLock); 00191 00192 /* Display separator + ReactOS version at start of the debug log */ 00193 DPRINT1("---------------------------------------------------------------\n"); 00194 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n"); 00195 MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024; 00196 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs); 00197 } 00198 else if (BootPhase == 2) 00199 { 00200 HalDisplayString("\n File log debugging enabled\n\n"); 00201 } 00202 else if (BootPhase == 3) 00203 { 00204 /* Setup the log name */ 00205 Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE); 00206 if (!NT_SUCCESS(Status)) return; 00207 00208 InitializeObjectAttributes(&ObjectAttributes, 00209 &FileName, 00210 0, 00211 NULL, 00212 NULL); 00213 00214 /* Create the log file */ 00215 Status = NtCreateFile(&KdpLogFileHandle, 00216 FILE_APPEND_DATA | SYNCHRONIZE, 00217 &ObjectAttributes, 00218 &Iosb, 00219 NULL, 00220 FILE_ATTRIBUTE_NORMAL, 00221 FILE_SHARE_READ, 00222 FILE_SUPERSEDE, 00223 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT, 00224 NULL, 00225 0); 00226 00227 RtlFreeUnicodeString(&FileName); 00228 00229 if (!NT_SUCCESS(Status)) return; 00230 00231 KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE); 00232 00233 /* Create the logger thread */ 00234 Status = PsCreateSystemThread(&ThreadHandle, 00235 THREAD_ALL_ACCESS, 00236 NULL, 00237 NULL, 00238 NULL, 00239 KdpLoggerThread, 00240 NULL); 00241 00242 if (!NT_SUCCESS(Status)) return; 00243 00244 Priority = 7; 00245 NtSetInformationThread(ThreadHandle, 00246 ThreadPriority, 00247 &Priority, 00248 sizeof(Priority)); 00249 } 00250 } 00251 00252 /* SERIAL FUNCTIONS **********************************************************/ 00253 00254 VOID 00255 NTAPI 00256 KdpSerialDebugPrint(LPSTR Message, 00257 ULONG Length) 00258 { 00259 KIRQL OldIrql; 00260 PCHAR pch = (PCHAR) Message; 00261 00262 /* Acquire the printing spinlock without waiting at raised IRQL */ 00263 while (TRUE) 00264 { 00265 /* Wait when the spinlock becomes available */ 00266 while (!KeTestSpinLock(&KdpSerialSpinLock)); 00267 00268 /* Spinlock was free, raise IRQL */ 00269 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 00270 00271 /* Try to get the spinlock */ 00272 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpSerialSpinLock)) 00273 break; 00274 00275 /* Someone else got the spinlock, lower IRQL back */ 00276 KeLowerIrql(OldIrql); 00277 } 00278 00279 /* Output the message */ 00280 while (*pch != 0) 00281 { 00282 if (*pch == '\n') 00283 { 00284 KdPortPutByteEx(&SerialPortInfo, '\r'); 00285 } 00286 KdPortPutByteEx(&SerialPortInfo, *pch); 00287 pch++; 00288 } 00289 00290 /* Release spinlock */ 00291 KiReleaseSpinLock(&KdpSerialSpinLock); 00292 00293 /* Lower IRQL */ 00294 KeLowerIrql(OldIrql); 00295 } 00296 00297 VOID 00298 NTAPI 00299 KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable, 00300 ULONG BootPhase) 00301 { 00302 SIZE_T MemSizeMBs; 00303 if (!KdpDebugMode.Serial) return; 00304 00305 if (BootPhase == 0) 00306 { 00307 /* Write out the functions that we support for now */ 00308 DispatchTable->KdpInitRoutine = KdpSerialInit; 00309 DispatchTable->KdpPrintRoutine = KdpSerialDebugPrint; 00310 00311 /* Initialize the Port */ 00312 if (!KdPortInitializeEx(&SerialPortInfo, 0, 0)) 00313 { 00314 KdpDebugMode.Serial = FALSE; 00315 return; 00316 } 00317 KdComPortInUse = (PUCHAR)(ULONG_PTR)SerialPortInfo.BaseAddress; 00318 00319 /* Initialize spinlock */ 00320 KeInitializeSpinLock(&KdpSerialSpinLock); 00321 00322 /* Register as a Provider */ 00323 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 00324 00325 /* Display separator + ReactOS version at start of the debug log */ 00326 DPRINT1("-----------------------------------------------------\n"); 00327 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n"); 00328 MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024; 00329 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs); 00330 DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions); 00331 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName, 00332 KeLoaderBlock->NtHalPathName, 00333 KeLoaderBlock->ArcHalDeviceName, 00334 KeLoaderBlock->NtBootPathName); 00335 } 00336 else if (BootPhase == 2) 00337 { 00338 HalDisplayString("\n Serial debugging enabled\n\n"); 00339 } 00340 } 00341 00342 /* SCREEN FUNCTIONS **********************************************************/ 00343 00344 /* 00345 * Screen debug logger function KdpScreenPrint() writes text messages into 00346 * KdpDmesgBuffer, using it as a circular buffer. KdpDmesgBuffer contents could 00347 * be later (re)viewed using dmesg command of kdbg. KdpScreenPrint() protects 00348 * KdpDmesgBuffer from simultaneous writes by use of KdpDmesgLogSpinLock. 00349 */ 00350 VOID 00351 NTAPI 00352 KdpScreenPrint(LPSTR Message, 00353 ULONG Length) 00354 { 00355 ULONG beg, end, num; 00356 KIRQL OldIrql; 00357 PCHAR pch = (PCHAR) Message; 00358 00359 while (*pch) 00360 { 00361 if(*pch == '\b') 00362 { 00363 /* HalDisplayString does not support '\b'. Workaround it and use '\r' */ 00364 if(KdpScreenLineLength > 0) 00365 { 00366 /* Remove last character from buffer */ 00367 KdpScreenLineBuffer[--KdpScreenLineLength] = '\0'; 00368 KdpScreenLineBufferPos = KdpScreenLineLength; 00369 00370 /* Clear row and print line again */ 00371 HalDisplayString("\r"); 00372 HalDisplayString(KdpScreenLineBuffer); 00373 } 00374 } 00375 else 00376 { 00377 KdpScreenLineBuffer[KdpScreenLineLength++] = *pch; 00378 KdpScreenLineBuffer[KdpScreenLineLength] = '\0'; 00379 } 00380 00381 if(*pch == '\n' || KdpScreenLineLength == KdpScreenLineLenght) 00382 { 00383 /* Print buffered characters */ 00384 if(KdpScreenLineBufferPos != KdpScreenLineLength) 00385 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 00386 00387 /* Clear line buffer */ 00388 KdpScreenLineBuffer[0] = '\0'; 00389 KdpScreenLineLength = KdpScreenLineBufferPos = 0; 00390 } 00391 00392 ++pch; 00393 } 00394 00395 /* Print buffered characters */ 00396 if(KdpScreenLineBufferPos != KdpScreenLineLength) 00397 { 00398 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 00399 KdpScreenLineBufferPos = KdpScreenLineLength; 00400 } 00401 00402 /* Dmesg: store Message in the buffer to show it later */ 00403 if (KdbpIsInDmesgMode) 00404 return; 00405 00406 if (KdpDmesgBuffer == NULL) 00407 return; 00408 00409 /* Acquire the printing spinlock without waiting at raised IRQL */ 00410 while (TRUE) 00411 { 00412 /* Wait when the spinlock becomes available */ 00413 while (!KeTestSpinLock(&KdpDmesgLogSpinLock)); 00414 00415 /* Spinlock was free, raise IRQL */ 00416 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 00417 00418 /* Try to get the spinlock */ 00419 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDmesgLogSpinLock)) 00420 break; 00421 00422 /* Someone else got the spinlock, lower IRQL back */ 00423 KeLowerIrql(OldIrql); 00424 } 00425 00426 /* Invariant: always_true(KdpDmesgFreeBytes == KdpDmesgBufferSize); 00427 * set num to min(KdpDmesgFreeBytes, Length). 00428 */ 00429 num = (Length < KdpDmesgFreeBytes) ? Length : KdpDmesgFreeBytes; 00430 beg = KdpDmesgCurrentPosition; 00431 if (num != 0) 00432 { 00433 end = (beg + num) % KdpDmesgBufferSize; 00434 if (end > beg) 00435 { 00436 RtlCopyMemory(KdpDmesgBuffer + beg, Message, Length); 00437 } 00438 else 00439 { 00440 RtlCopyMemory(KdpDmesgBuffer + beg, Message, KdpDmesgBufferSize - beg); 00441 RtlCopyMemory(KdpDmesgBuffer, Message + (KdpDmesgBufferSize - beg), end); 00442 } 00443 KdpDmesgCurrentPosition = end; 00444 00445 /* Counting the total bytes written */ 00446 KdbDmesgTotalWritten += num; 00447 } 00448 00449 /* Release spinlock */ 00450 KiReleaseSpinLock(&KdpDmesgLogSpinLock); 00451 00452 /* Lower IRQL */ 00453 KeLowerIrql(OldIrql); 00454 00455 /* Optional step(?): find out a way to notify about buffer exhaustion, 00456 * and possibly fall into kbd to use dmesg command: user will read 00457 * debug messages before they will be wiped over by next writes. 00458 */ 00459 } 00460 00461 VOID 00462 NTAPI 00463 KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable, 00464 ULONG BootPhase) 00465 { 00466 SIZE_T MemSizeMBs; 00467 if (!KdpDebugMode.Screen) return; 00468 00469 if (BootPhase == 0) 00470 { 00471 /* Write out the functions that we support for now */ 00472 DispatchTable->KdpInitRoutine = KdpScreenInit; 00473 DispatchTable->KdpPrintRoutine = KdpScreenPrint; 00474 00475 /* Register as a Provider */ 00476 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 00477 } 00478 else if (BootPhase == 1) 00479 { 00480 /* Allocate a buffer for dmesg log buffer. +1 for terminating null, 00481 * see kdbp_cli.c:KdbpCmdDmesg()/2 00482 */ 00483 KdpDmesgBuffer = ExAllocatePool(NonPagedPool, KdpDmesgBufferSize + 1); 00484 RtlZeroMemory(KdpDmesgBuffer, KdpDmesgBufferSize + 1); 00485 KdpDmesgFreeBytes = KdpDmesgBufferSize; 00486 KdbDmesgTotalWritten = 0; 00487 00488 /* Take control of the display */ 00489 InbvAcquireDisplayOwnership(); 00490 InbvResetDisplay(); 00491 InbvSolidColorFill(0, 0, 639, 479, 0); 00492 InbvSetTextColor(15); 00493 InbvSetScrollRegion(0, 0, 639, 479); 00494 InbvInstallDisplayStringFilter(NULL); 00495 InbvEnableDisplayString(TRUE); 00496 00497 /* Initialize spinlock */ 00498 KeInitializeSpinLock(&KdpDmesgLogSpinLock); 00499 00500 /* Display separator + ReactOS version at start of the debug log */ 00501 DPRINT1("-----------------------------------------------------\n"); 00502 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n"); 00503 MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024; 00504 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs); 00505 DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions); 00506 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName, 00507 KeLoaderBlock->NtHalPathName, 00508 KeLoaderBlock->ArcHalDeviceName, 00509 KeLoaderBlock->NtBootPathName); 00510 } 00511 else if (BootPhase == 2) 00512 { 00513 HalDisplayString("\n Screen debugging enabled\n\n"); 00514 } 00515 } 00516 00517 /* GENERAL FUNCTIONS *********************************************************/ 00518 00519 ULONG 00520 NTAPI 00521 KdpPrintString(LPSTR String, 00522 ULONG Length) 00523 { 00524 PLIST_ENTRY CurrentEntry; 00525 PKD_DISPATCH_TABLE CurrentTable; 00526 00527 if (!KdpDebugMode.Value) return 0; 00528 00529 /* Call the registered handlers */ 00530 CurrentEntry = KdProviders.Flink; 00531 while (CurrentEntry != &KdProviders) 00532 { 00533 /* Get the current table */ 00534 CurrentTable = CONTAINING_RECORD(CurrentEntry, 00535 KD_DISPATCH_TABLE, 00536 KdProvidersList); 00537 00538 /* Call it */ 00539 CurrentTable->KdpPrintRoutine(String, Length); 00540 00541 /* Next Table */ 00542 CurrentEntry = CurrentEntry->Flink; 00543 } 00544 00545 /* Call the Wrapper Routine */ 00546 if (WrapperTable.KdpPrintRoutine) 00547 WrapperTable.KdpPrintRoutine(String, Length); 00548 00549 /* Return the Length */ 00550 return Length; 00551 } 00552 00553 /* EOF */ Generated on Sun May 27 2012 04:37:19 for ReactOS by
1.7.6.1
|