/*++ Copyright (c) 2001 Microsoft Corporation Module Name: kdlite.c Abstract: This module implements the Xbox lite kernel debugger. --*/ #include "kdlitep.h" // // Stores whether or not the debugger is enabled. The debugger is only enabled // if a super I/O controller is present. // DECLSPEC_STICKY BOOLEAN KdDebuggerEnabled; // // Hardwired to TRUE, since a real debugger is never really present. // BOOLEAN KdDebuggerNotPresent = TRUE; // // Local support. // VOID KdpConfigureSerialPort( VOID ); VOID KdpInitializeLoadedModuleList( VOID ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, KdpConfigureSerialPort) #endif VOID KdpConfigureSerialPort( VOID ) /*++ Routine Description: This routine configures the serial port for the desired baud rate and port options. Arguments: None. Return Value: None. --*/ { ULONG DivisorLatch; DivisorLatch = CLOCK_RATE / KDLITE_DEBUG_BAUD_RATE; _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_LCR, 0x83); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_DLM, (UCHAR)(DivisorLatch >> 8)); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_DLL, (UCHAR)(DivisorLatch)); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_LCR, 0x03); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_MCR, MC_DTRRTS); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_IEN, 0); } VOID KdpPrintString( IN PSTRING String ) /*++ Routine Description: This routine prints out the supplied string to the serial port. Arguments: String - Specifies the string to be printed to the serial port. Return Value: None. --*/ { BOOLEAN Restore; ULONG Length; PUCHAR Buffer; // // If the debugger isn't enabled, don't do anything. // if (!KdDebuggerEnabled) { return; } // // Write out each character to the serial port. Synchronize by disabling // interrupts. // Restore = KiDisableInterrupts(); Length = String->Length; Buffer = String->Buffer; while (Length > 0) { while (!(_inp(KDLITE_DEBUG_BASE_ADDRESS + COM_LSR) & COM_OUTRDY)); _outp(KDLITE_DEBUG_BASE_ADDRESS + COM_DAT, *Buffer); Length--; Buffer++; } KiRestoreInterrupts(Restore); } BOOLEAN KdpTrap( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN BOOLEAN SecondChance ) /*++ Routine Description: This routine is called whenever a exception is dispatched. Arguments: TrapFrame - Supplies a pointer to a trap frame that describes the trap. ExceptionFrame - Supplies a pointer to a exception frame that describes the trap. ExceptionRecord - Supplies a pointer to an exception record that describes the exception. ContextRecord - Supplies the context at the time of the exception. SecondChance - Supplies a boolean value that determines whether this is the second chance (TRUE) that the exception has been raised. Return Value: A value of TRUE is returned if the exception is handled. Otherwise a value of FALSE is returned. --*/ { BOOLEAN Handled = FALSE; if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->NumberParameters > 0) && ((ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_LOAD_SYMBOLS)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_UNLOAD_SYMBOLS)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_LOAD_XESECTION)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_UNLOAD_XESECTION)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_KDPRINT)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_PRINT))) { if ((ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_KDPRINT)|| (ExceptionRecord->ExceptionInformation[0] == BREAKPOINT_PRINT)) { KdpPrintString((PSTRING)ExceptionRecord->ExceptionInformation[1]); ContextRecord->Eax = STATUS_SUCCESS; } ContextRecord->Eip++; Handled = TRUE; } return Handled; } VOID KdInitSystem( BOOLEAN InitializingSystem ) /*++ Routine Description: This routine initializes the lite kernel debugger. Arguments: InitializingSystem - Supplies a boolean value that determines whether we're called in the context of system initialization or bugcheck code. Return Value: None. --*/ { if (InitializingSystem) { // // If the kernel is cold-booting, then determine whether or not a super // I/O controller is attached to the system so that we know whether or // not to output debug spew through the serial port. // if (!KeHasQuickBooted) { HalPulseHardwareMonitorPin(); KdDebuggerEnabled = HalInitializeSuperIo(); if (KdDebuggerEnabled) { KdpConfigureSerialPort(); } } // // Set the debug routine to point at our trap handler. // KiDebugRoutine = KdpTrap; #ifdef DEVKIT // // For DEVKIT builds of this library, we still need to initialize the // module list so that the debug monitor will continue to function. // KdpInitializeLoadedModuleList(); #endif } } #ifdef DEVKIT // // The following code and data are present for DEVKIT builds to enable testing // of the lite kernel debugger on a DEVKIT platform. None of this code is used // by a retail build of the system. // // // Set to TRUE if the are any breakpoints that need to be applied to pages that // are not inpaged. Always FALSE since this implementation never applies // breakpoints. // BOOLEAN KdpOweBreakpoint; // // Static loader data table entry for XBOXKRNL.EXE. // LDR_DATA_TABLE_ENTRY KdpNtosDataTableEntry; // // List of modules that have been loaded. // INITIALIZED_LIST_ENTRY(KdLoadedModuleList); VOID KdpInitializeLoadedModuleList( VOID ) /*++ Routine Description: This routine initializes the static loader data table entry for the kernel and attaches it to the loaded module list. Arguments: None. Return Value: None. --*/ { // // Initialize the loader data table entry for XBOXKRNL.EXE and attach it // to the loaded module list. // KdpNtosDataTableEntry.DllBase = PsNtosImageBase; KdpNtosDataTableEntry.SizeOfImage = RtlImageNtHeader(PsNtosImageBase)->OptionalHeader.SizeOfImage; KdpNtosDataTableEntry.LoadedImports = (PVOID)MAXULONG_PTR; RtlInitUnicodeString(&KdpNtosDataTableEntry.FullDllName, L"xboxkrnl.exe"); RtlInitUnicodeString(&KdpNtosDataTableEntry.BaseDllName, L"xboxkrnl.exe"); InsertTailList(&KdLoadedModuleList, &KdpNtosDataTableEntry.InLoadOrderLinks); } BOOLEAN KdPollBreakIn( VOID ) /*++ Routine Description: This routine checks if a breakin packet is pending. Arguments: None. Return Value: Returns FALSE to indicate that no breakin packet is pending. --*/ { return FALSE; } VOID KdSetOwedBreakpoints( VOID ) /*++ Routine Description: This routine is called by the page fault handler to store pending breakpoints for pages that may have been just made valid. Arguments: None. Return Value: None. --*/ { // // This routine should never be called because this implementation never // applies breakpoints and never sets KdpOweBreakpoint to TRUE. // KeBugCheck(0); } VOID KdDeleteAllBreakpoints( VOID ) /*++ Routine Description: This routine is called to delete all breakpoints from the system. Arguments: None. Return Value: None. --*/ { NOTHING; } #endif