/** * @file * * AMD Integrated Debug Debug_library Routines * * Contains AMD AGESA debug macros and library functions * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: IDS * @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $ */ /***************************************************************************** * Copyright (c) 2011, Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /*---------------------------------------------------------------------------------------- * M O D U L E S U S E D *---------------------------------------------------------------------------------------- */ #include "AGESA.h" #include "Ids.h" #include "IdsLib.h" #include "amdlib.h" #include "AMD.h" #include "heapManager.h" #include "cpuRegisters.h" #include "Filecode.h" #define FILECODE PROC_IDS_DEBUG_IDSDEBUG_FILECODE extern BUILD_OPT_CFG UserOptions; typedef struct _IDS_CONSOLE IDS_CONSOLE; /*--------------------------------------------------------------------------------------*/ /** * IDS back-end code for AGESA_TESTPOINT * * @param[in] TestPoint Progress indicator value, see @ref AGESA_TP * @param[in,out] StdHeader The Pointer of AGESA Header * **/ /*--------------------------------------------------------------------------------------*/ VOID IdsAgesaTestPoint ( IN AGESA_TP TestPoint, IN OUT AMD_CONFIG_PARAMS *StdHeader ) { LibAmdIoWrite (AccessWidth8, IDS_DEBUG_PORT, &TestPoint, StdHeader); IDS_PERF_TIMESTAMP (StdHeader, TestPoint); if (TestPoint == EndAgesaTps) { IDS_PERF_ANALYSE (StdHeader); } } #define DEBUG_PRINT_INIT 0x10BF0000 #define DEBUG_PRINT_EXIT 0xE0BF0000 #define DEBUG_PRINT_COMMAND 0xC0BF0000 #define DEBUG_PRINT_BREAKPOINT 0xB0BF0000 #define DEBUG_PRINT_EVENT 0x1EBF0000 #define IDS_HDTOUT_BPFLAG_FORMAT_STR 0 #define IDS_HDTOUT_BPFLAG_STATUS_STR 1 #define HDTOUT_BP_ACTION_HALT 1 #define HDTOUT_BP_ACTION_PRINTON 2 #define HDTOUT_BP_ACTION_PRINTONE 3 #define HDTOUT_BP_ACTION_PRINTOFF 4 typedef struct _BREAKPOINT_UNIT { UINT8 AndFlag : 1; ///< Next string is ANDed to current string UINT8 BpFlag : 1; ///< Format string or Status string UINT8 Action : 4; ///< Halt, start HDTOUT, or stop HDT,... UINT8 BpStrOffset; ///< Offset from BreakpointList to the breakpoint string } BREAKPOINT_UNIT; typedef enum { IDS_STATE_OFF = 0xF0, IDS_STATE_ON } IDS_STATE_TYPE; typedef enum { NON_CONSOLE = 0xD0, HDT_CONSOLE, IDS_CONSOLE_END } IDS_CONSOLE_TYPE; // IDS HdtOut Event Level typedef enum { EVENT_OFF = 0x30, ///< Default,no event triggered. EVENT_WARNING, ///< Event warning. EVENT_ERROR, ///< Event error. EVENT_FAIL_BUFFER_ALLOCATION, ///< Reserved, fail buffer allocation EVENT_END ///< Event end sentinel. } CONSOLE_EVENT_TYPE; #define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) // // Also support coding convention rules for var arg macros // typedef CHAR8 *VA_LIST; #define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v)) #define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t))) #define VA_END(ap) (ap = (VA_LIST) 0) #define LEFT_JUSTIFY 0x01 #define PREFIX_SIGN 0x02 #define PREFIX_BLANK 0x04 #define COMMA_TYPE 0x08 #define LONG_TYPE 0x10 #define PREFIX_ZERO 0x20 /** * Create console context * * Do hardware settings related with specific console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_CREATE_CONSOLE_CONTEXT ( IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_CREATE_CONSOLE_CONTEXT *PF_CREATE_CONSOLE_CONTEXT; /** * Initialize console context * * Initilize preference settings related with specific console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_INIT_CONSOLE_CONTEXT ( IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_INIT_CONSOLE_CONTEXT *PF_INIT_CONSOLE_CONTEXT; /** * Update console context * * Update preference settings related with specific console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_UPDATE_CONSOLE_CONTEXT ( IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_UPDATE_CONSOLE_CONTEXT *PF_UPDATE_CONSOLE_CONTEXT; /** * Save console context * * Save console context snapshot * * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_SAVE_CONSOLE_CONTEXT ( IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_SAVE_CONSOLE_CONTEXT *PF_SAVE_CONSOLE_CONTEXT; /** * Destroy console context * * Destroy console context snapshot * * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_DESTROY_CONSOLE_CONTEXT ( IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_DESTROY_CONSOLE_CONTEXT *PF_DESTROY_CONSOLE_CONTEXT; /** * Print function * * Print function related with specific console * * @param[in] PrintType Print Type * @param[in] ConsoleBufferAddress The address of console buffer * @param[in] ConsoleBufferSize The size of console buffer * @param[in,out] IdsConsole The Pointer of IDS console * **/ typedef VOID F_PRINT ( IN UINT32 PrintType, IN UINT32 ConsoleBufferAddress, IN UINT32 ConsoleBufferSize, IN OUT IDS_CONSOLE *IdsConsole ); /// Reference to a method. typedef F_PRINT *PF_PRINT; /// IDS Console Operations typedef struct _IDS_CONSOLE_OPERATIONS { PF_CREATE_CONSOLE_CONTEXT CreateConsoleContext; PF_INIT_CONSOLE_CONTEXT InitConsoleContext; PF_UPDATE_CONSOLE_CONTEXT UpdateConsoleContext; PF_DESTROY_CONSOLE_CONTEXT DestroyConsoleContext; PF_PRINT Print; } IDS_CONSOLE_OPERATIONS; /// IDS Console Header typedef struct _IDS_CONSOLE_HEADER { UINT32 Signature; ///< Signature information. UINT32 Version; ///< Version. UINT8 ConsoleType; ///< Console type UINT8 Event; ///< Event type. UINT8 PrintState; ///< On or Off UINT8 OutBufferMode; ///< Off:stack mode, On: heap mode UINT16 OutBufferSize; ///< Buffer size UINT16 OutBufferIndex; ///< Buffer index UINT32 NumBreakpointUnit; ///< default 0 no bp unit others number of bp unit } IDS_CONSOLE_HEADER; /// IDS Console struct _IDS_CONSOLE { IDS_CONSOLE_HEADER Header; /**< IDS console header - 5 dwords */ UINT32 FuncListAddr; /**< 32 bit address to the list of functions that script can execute */ UINT8 Reserved[56 - 24]; /**< ----------------- New fields must be added here. */ CHAR8 BreakpointList[300]; /**< Breakpoint list */ CHAR8 StatusStr[156]; /**< Shows current node, DCT, CS,... */ CHAR8 OutBuffer[2]; /**< Console Out content. Its size will be determined by BufferSize. */ }; /** * Create hdt console context * * Do hardware settings for hdt console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ STATIC VOID CreateHdtConsoleContext ( IN OUT IDS_CONSOLE *IdsConsole ) { UINT64 SMsr; UINT32 CR4reg; LibAmdMsrRead (0xC001100A, (UINT64*)&SMsr, NULL); SMsr |= 1; LibAmdMsrWrite (0xC001100A, (UINT64*)&SMsr, NULL); LibAmdWriteCpuReg (DR2_REG, 0x99CC); LibAmdWriteCpuReg (DR7_REG, 0x02000420); LibAmdReadCpuReg (CR4_REG, &CR4reg); LibAmdWriteCpuReg (CR4_REG, CR4reg | ((UINT32)1 << 3)); } /** * Initialize hdt console context * * Initilize preference settings for hdt console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ STATIC VOID InitHdtConsoleContext ( IN OUT IDS_CONSOLE *IdsConsole ) { IDS_FUNCLIST_EXTERN (); IdsConsole->FuncListAddr = (UINT32) IDS_FUNCLIST_ADDR; IdsConsole->StatusStr[0] = 0; } /** * Update hdt console context * * Update preference settings for hdt console context * * @param[in,out] IdsConsole The Pointer of IDS console * **/ STATIC VOID UpdateHdtConsoleContext ( IN OUT IDS_CONSOLE *IdsConsole ) { if (IdsConsole->Header.OutBufferMode == IDS_STATE_OFF) { IdsConsole->Header.OutBufferSize = 0; } } /** * Destroy hdt console context * * Save hdt console context snapshot * * @param[in,out] IdsConsole The Pointer of IDS console * **/ STATIC VOID DestroyHdtConsoleContext ( IN OUT IDS_CONSOLE *IdsConsole ) { UINT64 SMsr; LibAmdMsrRead (0xC001100A, (UINT64 *)&SMsr, NULL); SMsr &= ~BIT0; LibAmdMsrWrite (0xC001100A, (UINT64 *)&SMsr, NULL); LibAmdWriteCpuReg (DR2_REG, 0); LibAmdWriteCpuReg (DR3_REG, 0); LibAmdWriteCpuReg (DR7_REG, 0); } /** * Hdt console print function * * Print function related with hdt console * * @param[in] PrintType Print Type * @param[in] ConsoleBufferAddress The address of console buffer * @param[in] ConsoleBufferSize The size of console buffer * @param[in,out] IdsConsole The Pointer of IDS console * **/ STATIC VOID HdtConsolePrint ( IN UINT32 PrintType, IN UINT32 ConsoleBufferAddress, IN UINT32 ConsoleBufferSize, IN OUT IDS_CONSOLE *IdsConsole ) { IdsOutPort (PrintType | 0x99CC, ConsoleBufferAddress, ConsoleBufferSize); } /// Initial construction data for HDT console header. CONST IDS_CONSOLE_HEADER ROMDATA HdtConsoleHeader = { 0xDB1099CC, 0x0100, IDS_STATE_ON, EVENT_OFF, IDS_STATE_ON, IDS_STATE_ON, 0x1000, 0x0, 0, }; #define OPTION_HDT_CONSOLE_HEADER &HdtConsoleHeader /// Initial construction data for HDT console operations. CONST IDS_CONSOLE_OPERATIONS ROMDATA HdtConsoleOperations = { CreateHdtConsoleContext, InitHdtConsoleContext, UpdateHdtConsoleContext, DestroyHdtConsoleContext, HdtConsolePrint }; #define OPTION_HDT_CONSOLE_OPERATIONS &HdtConsoleOperations /** * Parses flag and width information from theFormat string and returns the next index * into the Format string that needs to be parsed. See file headed for details of Flag and Width. * * @param[in] Format Current location in the AvSPrint format string. * @param[out] Flags Returns flags * @param[out] Width Returns width of element * @param[out] Marker Vararg list that may be partially consumed and returned. * * @retval Pointer indexed into the Format string for all the information parsed by this routine. * **/ STATIC CHAR8 * GetFlagsAndWidth ( IN CHAR8 *Format, OUT UINTN *Flags, OUT UINTN *Width, IN OUT VA_LIST *Marker ) { UINTN Count; BOOLEAN Done; *Flags = 0; *Width = 0; for (Done = FALSE; !Done; ) { Format++; switch (*Format) { case '-': *Flags |= LEFT_JUSTIFY; break; case '+': *Flags |= PREFIX_SIGN; break; case ' ': *Flags |= PREFIX_BLANK; break; case ',': *Flags |= COMMA_TYPE; break; case 'L': case 'l': *Flags |= LONG_TYPE; break; case '*': *Width = VA_ARG (*Marker, UINTN); break; case '0': *Flags |= PREFIX_ZERO; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': Count = 0; do { Count = (Count * 10) + *Format - '0'; Format++; } while ((*Format >= '0') && (*Format <= '9')); Format--; *Width = Count; break; default: Done = TRUE; } } return Format; } CHAR8 STATIC HexStr[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * * @param[in] Buffer Location to place ascii hex string of Value. * @param[in] Value - Hex value to convert to a string in Buffer. * @param[in] Flags - Flags to use in printing Hex string, see file header for details. * @param[in] Width - Width of hex value. * * @retval Number of characters printed. **/ STATIC UINTN ValueTomHexStr ( IN OUT CHAR8 *Buffer, IN UINT64 Value, IN UINTN Flags, IN UINTN Width ) { CHAR8 TempBuffer[30]; CHAR8 *TempStr; CHAR8 Prefix; CHAR8 *BufferPtr; UINTN Count; UINTN Index; TempStr = TempBuffer; BufferPtr = Buffer; // // Count starts at one since we will null terminate. Each iteration of the // loop picks off one nibble. Oh yea TempStr ends up backwards // Count = 0; do { *(TempStr++) = HexStr[Value & 0x0f]; Value >>= 4; Count++; } while (Value != 0); if (Flags & PREFIX_ZERO) { Prefix = '0'; } else if (!(Flags & LEFT_JUSTIFY)) { Prefix = ' '; } else { Prefix = 0x00; } for (Index = Count; Index < Width; Index++) { *(TempStr++) = Prefix; } // // Reverse temp string into Buffer. // while (TempStr != TempBuffer) { *(BufferPtr++) = *(--TempStr); } *BufferPtr = 0; return Index; } /** * Prints a Value as a decimal number in Buffer * * @param[in] Buffer Location to place ascii decimal number string of Value. * @param[in] Value Decimal value to convert to a string in Buffer. * @param[in] Flags Flags to use in printing decimal string, see file header for details. * * @retval Number of characters printed. * **/ STATIC UINTN ValueToString ( IN OUT CHAR8 *Buffer, IN INT32 Value, IN UINTN Flags ) { CHAR8 TempBuffer[30]; CHAR8 *TempStr; CHAR8 *BufferPtr; UINTN Count; UINTN Remainder; TempStr = TempBuffer; BufferPtr = Buffer; Count = 0; if (Value < 0) { *(BufferPtr++) = '-'; Value = - Value; Count++; } do { Remainder = Value % 10; Value /= 10; *(TempStr++) = (CHAR8)(Remainder + '0'); Count++; if ((Flags & COMMA_TYPE) == COMMA_TYPE) { if (Count % 3 == 0) { *(TempStr++) = ','; } } } while (Value != 0); // // Reverse temp string into Buffer. // while (TempStr != TempBuffer) { *(BufferPtr++) = *(--TempStr); } *BufferPtr = 0; return Count; } /** * Check if String contain the substring * * @param[in] String Pointer of string. * @param[in] Substr Pointer of sub string. * * @retval TRUE S2 is substring of S1 * @retval FALSE S2 isn't substring of S1 * **/ STATIC BOOLEAN AmdIdsSubStr ( IN CHAR8 *String, IN CHAR8 *Substr ) { UINT16 i; UINT16 j; for (i = 0; String[i] != 0 ; i++) { for (j = 0; (Substr[j] != 0) && (Substr[j] == String[i + j]); j++) { } if (Substr[j] == 0) { return TRUE; } } return FALSE; } /** * IDS Backend Function for Memory timeout control * * This function is used to override Memory timeout control. * * @param[in,out] DataPtr The Pointer of UINT8. * **/ VOID IdsMemTimeOut ( IN OUT VOID *DataPtr ) { UINT32 DR2reg; LibAmdReadCpuReg (DR2_REG, &DR2reg); if (DR2reg == 0x99CC) { // Turn timeout off if HDTout is on *((UINT8 *)DataPtr) = (UINT8)0; } } /** * * IDS Debug Function to check the sentinels are intact * * This function complete heap walk and check to be performed at any time. * * @param[in] StdHeader Config handle for library and services. * * @retval TRUE No error * **/ BOOLEAN AmdHeapIntactCheck ( IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 *HeapBufferPtr; BUFFER_NODE *StartOfBufferPtr; BUFFER_NODE *EndOfBufferPtr; HEAP_MANAGER *HeapManagerPtr; BUFFER_NODE *HeadNodePtr; BUFFER_NODE *CurrentNodePtr; UINT32 AmdHeapRamAddress; UINT32 SentinelBefore; UINT32 SentinelAfter; ASSERT (StdHeader != NULL); AmdHeapRamAddress = (UINT32)UserOptions.CfgHeapDramAddress; if (StdHeader->HeapStatus == HEAP_LOCAL_CACHE) { HeapBufferPtr = (UINT8 *) HeapGetCurrentBase (StdHeader); } else if (StdHeader->HeapStatus == HEAP_TEMP_MEM) { HeapBufferPtr = (UINT8 *) AmdHeapRamAddress; } else { return TRUE; } HeapManagerPtr = (HEAP_MANAGER *) HeapBufferPtr; HeadNodePtr = (BUFFER_NODE *) (HeapBufferPtr + sizeof (HEAP_MANAGER)); CurrentNodePtr = HeadNodePtr; if (HeapManagerPtr->AvailableSize != AMD_HEAP_SIZE_PER_CORE - sizeof (HEAP_MANAGER)) { while (CurrentNodePtr != NULL) { StartOfBufferPtr = (BUFFER_NODE *) ((UINT8 *) CurrentNodePtr + sizeof (BUFFER_NODE) + CurrentNodePtr->BufferSize + 2 * SIZE_OF_SENTINEL); EndOfBufferPtr = (BUFFER_NODE *) ((UINT8 *) HeadNodePtr + AMD_HEAP_SIZE_PER_CORE); if (CurrentNodePtr->NextNodePtr != NULL) { ASSERT ((CurrentNodePtr->NextNodePtr >= StartOfBufferPtr) && (CurrentNodePtr->NextNodePtr < EndOfBufferPtr)); SentinelBefore = *(UINT32 *) ((UINT8 *) CurrentNodePtr + sizeof (BUFFER_NODE)); SentinelAfter = *(UINT32 *) ((UINT8 *) CurrentNodePtr + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + CurrentNodePtr->BufferSize); ASSERT ((SentinelBefore == SENTINEL_BEFORE_VALUE) && (SentinelAfter == SENTINEL_AFTER_VALUE)); } else { ASSERT ((UINT8 *) StartOfBufferPtr == HeapBufferPtr + AMD_HEAP_SIZE_PER_CORE - HeapManagerPtr->AvailableSize); SentinelBefore = *(UINT32 *) ((UINT8 *) CurrentNodePtr + sizeof (BUFFER_NODE)); SentinelAfter = *(UINT32 *) ((UINT8 *) CurrentNodePtr + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + CurrentNodePtr->BufferSize); ASSERT ((SentinelBefore == SENTINEL_BEFORE_VALUE) && (SentinelAfter == SENTINEL_AFTER_VALUE)); } CurrentNodePtr = CurrentNodePtr->NextNodePtr; } } return TRUE; } /** * Determine whether IDS console is enabled. * * @param[in,out] IdsConsole The Pointer of Ids console data * * @retval TRUE Ids console is enabled. * @retval FALSE Ids console is disabled. * **/ BOOLEAN STATIC IsIdsConsoleEnabled ( IN OUT UINTN *IdsConsole ) { BOOLEAN Result; UINT32 DR2reg; Result = FALSE; LibAmdReadCpuReg (DR2_REG, &DR2reg); if (DR2reg == 0x99CC) { Result = TRUE; } return Result; } /** * Get IDS console. * * @param[in,out] IdsConsolePtr The Pointer of Ids console data * **/ STATIC VOID GetIdsConsole ( IN OUT UINTN *IdsConsolePtr ) { UINT32 DR3Reg; LibAmdReadCpuReg (DR3_REG, &DR3Reg); *IdsConsolePtr = (UINTN) DR3Reg; } /** * Get IDS console operations. * * @param[in,out] IdsConsoleOperations The Pointer of Ids console operations * **/ STATIC VOID GetIdsConsoleHeader ( IN OUT UINTN *IdsConsoleHeader ) { IDS_CONSOLE_TYPE IdsConsoleType; IdsConsoleType = (IDS_CONSOLE_TYPE) OPTION_IDS_CONSOLE; if (IdsConsoleType == HDT_CONSOLE) { *IdsConsoleHeader = (UINTN) OPTION_HDT_CONSOLE_HEADER; } else { ASSERT (FALSE); } } /** * Get IDS console operations. * * @param[in,out] IdsConsoleOperations The Pointer of Ids console operations * **/ STATIC VOID GetIdsConsoleOperations ( IN OUT UINTN *IdsConsoleOperations ) { IDS_CONSOLE_TYPE IdsConsoleType; IdsConsoleType = (IDS_CONSOLE_TYPE) OPTION_IDS_CONSOLE; if (IdsConsoleType == HDT_CONSOLE) { *IdsConsoleOperations = (UINTN) OPTION_HDT_CONSOLE_OPERATIONS; } else { ASSERT (FALSE); } } /** * Create IDS console. * * @param[in,out] IdsConsole The Pointer of Ids console data * @param[in,out] StdHeader The Pointer of AGESA Header **/ STATIC VOID NewIdsConsole ( IN OUT IDS_CONSOLE *IdsConsole, IN OUT AMD_CONFIG_PARAMS *StdHeader ) { IDS_CONSOLE_HEADER *IdsConsoleHeader; UINTN IdsConsoleHeaderPtr; GetIdsConsoleHeader (&IdsConsoleHeaderPtr); IdsConsoleHeader = &(IdsConsole->Header); LibAmdMemCopy ((VOID *)IdsConsoleHeader, (VOID *) (IdsConsoleHeaderPtr), (UINT32) sizeof (IDS_CONSOLE_HEADER), StdHeader); } /** * Destroy IDS console. * * @param[in,out] IdsConsole The Pointer of Ids console data * @param[in,out] StdHeader The Pointer of AGESA Header **/ STATIC VOID DestroyIdsConsole ( IN OUT IDS_CONSOLE *IdsConsole, IN OUT AMD_CONFIG_PARAMS *StdHeader ) { HeapDeallocateBuffer (IDS_HDT_OUT_BUFFER_HANDLE, StdHeader); } /** * Save IDS console Snapshot. * * @param[in,out] IdsConsole The Pointer of Ids console data * @param[in,out] StdHeader The Pointer of AGESA Header **/ STATIC VOID SaveIdsConsole ( IN OUT IDS_CONSOLE *IdsConsole, IN OUT IDS_CONSOLE_OPERATIONS *IdsConsoleOps, IN OUT AMD_CONFIG_PARAMS *StdHeader ) { ALLOCATE_HEAP_PARAMS AllocHeapParams; do { AllocHeapParams.RequestedBufferSize = IdsConsole->Header.OutBufferSize + sizeof (IDS_CONSOLE) - 2; AllocHeapParams.BufferHandle = IDS_HDT_OUT_BUFFER_HANDLE; AllocHeapParams.Persist = HEAP_SYSTEM_MEM; if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) { break; } else { IdsConsole->Header.OutBufferSize -= 256; IdsConsole->Header.Event = EVENT_FAIL_BUFFER_ALLOCATION; IdsConsoleOps->Print (DEBUG_PRINT_EVENT, (UINT32)IdsConsole, 0, IdsConsole); } } while ((IdsConsole->Header.OutBufferSize & 0x8000) == 0); if ((IdsConsole->Header.OutBufferSize & 0x8000) == 0) { LibAmdWriteCpuReg (DR3_REG, (UINT32)AllocHeapParams.BufferPtr); LibAmdMemCopy (AllocHeapParams.BufferPtr, (VOID *) IdsConsole, (UINT32) sizeof (IDS_CONSOLE) - 2, StdHeader); } } /** * * Initial function for IDS console. * * Create IDS console context, let Ids console function to be ready. * * @param[in,out] StdHeader The Pointer of AGESA Header * **/ VOID AmdIdsConsoleInit ( IN OUT AMD_CONFIG_PARAMS *StdHeader ) { IDS_CONSOLE IdsConsole; IDS_CONSOLE_OPERATIONS *IdsConsoleOps; UINTN IdsConsolePtr; UINTN IdsConsoleOpsPtr; if (IsIdsConsoleEnabled (&IdsConsolePtr)) { GetIdsConsoleOperations (&IdsConsoleOpsPtr); IdsConsoleOps = (IDS_CONSOLE_OPERATIONS *) IdsConsoleOpsPtr; NewIdsConsole (&IdsConsole, StdHeader); IdsConsoleOps->CreateConsoleContext (&IdsConsole); IdsConsoleOps->InitConsoleContext (&IdsConsole); IdsConsoleOps->Print (DEBUG_PRINT_INIT, (UINT32)&IdsConsole, 0, &IdsConsole); IdsConsoleOps->UpdateConsoleContext (&IdsConsole); SaveIdsConsole (&IdsConsole, IdsConsoleOps, StdHeader); } } /** * Prints string to debug host like printf in C * * @param[in] Format of string * @param[in] ... Variable parameter * **/ VOID AmdIdsConsolePrint ( IN CHAR8 *Format, IN ... ) { IDS_CONSOLE *IdsConsole; UINTN IdsConsolePtr; IDS_CONSOLE_OPERATIONS *IdsConsoleOps; UINTN IdsConsoleOpsPtr; VA_LIST Marker; CHAR8 LocalBuffer[256]; CHAR8 *ConsoleBuffer; CHAR8 Null_Str[] = " < null string > "; CHAR8 *AsciiStr; UINTN Index; UINTN Flags; UINTN Width; UINTN ConsoleBufferSize; UINT64 Value; UINT16 *Array; UINT32 ArrayLength; UINT32 ArrayIndex; BOOLEAN SaveStatus; UINT32 LastIndex; UINT32 i; UINT32 j; UINT32 NumBpUnit; BREAKPOINT_UNIT *Pbpunit; CHAR8 *Pbpstr; CHAR8 *PCmpStr; CHAR8 *EventLevelStr; BOOLEAN LastBpmatched; BOOLEAN Bpmatched; IDS_STATE_TYPE PrintCtrl; //Init the default Value IdsConsole = NULL; IdsConsolePtr = 0; ConsoleBuffer = LocalBuffer; Index = 0; LastIndex = 0; ConsoleBufferSize = 256; NumBpUnit = 0; PrintCtrl = IDS_STATE_ON; if (IsIdsConsoleEnabled (&IdsConsolePtr)) { GetIdsConsole (&IdsConsolePtr); IdsConsole = (IDS_CONSOLE *) IdsConsolePtr; GetIdsConsoleOperations (&IdsConsoleOpsPtr); IdsConsoleOps = (IDS_CONSOLE_OPERATIONS *) IdsConsoleOpsPtr; if (IdsConsole->Header.OutBufferMode == IDS_STATE_ON) { ConsoleBuffer = IdsConsole->OutBuffer; Index = IdsConsole->Header.OutBufferIndex; ConsoleBufferSize = (UINTN) (IdsConsole->Header.OutBufferSize); NumBpUnit = IdsConsole->Header.NumBreakpointUnit; PrintCtrl = IdsConsole->Header.PrintState; } if ((PrintCtrl != 0) || (NumBpUnit > 0)) { VA_START(Marker,Format); //init marker to 1st dynamic parameters. LastIndex = (UINT32) Index; if (*Format != '@') { if (*Format == '!') { SaveStatus = TRUE; Format++; } else { SaveStatus = FALSE; } for (; *Format != '\0'; Format++) { if (*Format != '%') { ConsoleBuffer[Index++] = *Format; } else { Format = GetFlagsAndWidth (Format, &Flags, &Width, &Marker); switch (*Format) { // Using %[EventType] style to catch predefined event. case '[': EventLevelStr = Format; EventLevelStr++; if ((*EventLevelStr > EVENT_OFF) && (*EventLevelStr < EVENT_END)) { EventLevelStr++; if (*EventLevelStr == ']') { EventLevelStr--; IdsConsole->Header.Event = (UINT8) (CONSOLE_EVENT_TYPE) (*EventLevelStr); } } break; case 'X': Flags |= PREFIX_ZERO; Width = sizeof (UINT64) * 2; // // break skipped on purpose // case 'x': if ((Flags & LONG_TYPE) == LONG_TYPE) { Value = VA_ARG (Marker, UINT64); } else { Value = VA_ARG (Marker, UINTN); } Index += ValueTomHexStr (&ConsoleBuffer[Index], Value, Flags, Width); break; case 'd': Value = (UINTN)VA_ARG (Marker, UINT32); Index += ValueToString (&ConsoleBuffer[Index], (UINT32)Value, Flags); break; case 's': case 'S': AsciiStr = (CHAR8 *)VA_ARG (Marker, CHAR8 *); if (AsciiStr == NULL) { AsciiStr = Null_Str; //" < null string > "; } while (*AsciiStr != '\0') { ConsoleBuffer[Index++] = *AsciiStr++; } break; case 'c': ConsoleBuffer[Index++] = (CHAR8)VA_ARG (Marker, UINTN); break; case 'a': Array = (UINT16 *) VA_ARG (Marker, VOID *); ArrayLength = (UINT32) VA_ARG (Marker, UINT32); for (ArrayIndex = 0; ArrayIndex < ArrayLength; ArrayIndex++) { // Only support hex format of an array of UINT16 for now. Width = 2; Flags = PREFIX_ZERO; ConsoleBuffer[Index++] = ' '; Index += ValueTomHexStr (&ConsoleBuffer[Index], Array[ArrayIndex] & 0xFF, Flags, Width); // If buffer is full if (Index > (ConsoleBufferSize - 8)) { if (IdsConsole != NULL) { if (LastIndex != 0) { // Stream all out except current string if (PrintCtrl != 0) { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, LastIndex, IdsConsole); } Index = Index - LastIndex; // Move current string too top for (i = 0; i < Index; i++) { ConsoleBuffer[i] = ConsoleBuffer[LastIndex + i]; } LastIndex = 0; } else { // Buffer size is too small ASSERT (FALSE); } } else { break; } } } break; case 'v': ConsoleBuffer[Index++] = '%'; ConsoleBuffer[Index++] = 'v'; Format++; ConsoleBuffer[Index++] = *Format; if (*Format == 'h') { Format++; ConsoleBuffer[Index++] = *Format; } break; case '%': ConsoleBuffer[Index++] = *Format; break; default: // // if the type is unknown print it to the screen // ConsoleBuffer[Index++] = '%'; ConsoleBuffer[Index++] = *Format; } } // If buffer is full if (Index > (ConsoleBufferSize - 32)) { if (IdsConsole != NULL) { if (LastIndex != 0) { // Stream all out except current string if (PrintCtrl != IDS_STATE_OFF) { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, LastIndex, IdsConsole); } Index = Index - LastIndex; // Move current string too top for (i = 0; i < Index; i++) { ConsoleBuffer[i] = ConsoleBuffer[LastIndex + i]; } LastIndex = 0; } else { // Buffer size is too small ASSERT (FALSE); } } else { break; } } } if (IdsConsole->Header.OutBufferMode == IDS_STATE_OFF) { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, (UINT32) Index, IdsConsole); Index = 0; } if ((IdsConsole->Header.Event > EVENT_OFF) && (IdsConsole->Header.Event < EVENT_END) ) { // if HdtOut Buffer is on, flush hdtout buffer contents out. if (IdsConsole->Header.OutBufferMode == IDS_STATE_ON) { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, (UINT32) Index, IdsConsole); Index = 0; } IdsConsoleOps->Print (DEBUG_PRINT_EVENT, (UINT32)IdsConsole, 0, IdsConsole); IdsConsole->Header.Event = EVENT_OFF; } // // Check breakpoint // if (NumBpUnit) { Pbpunit = (BREAKPOINT_UNIT *) IdsConsole->BreakpointList; LastBpmatched = TRUE; Bpmatched = TRUE; for (i = 0; i < NumBpUnit; i++) { Pbpstr = IdsConsole->BreakpointList + Pbpunit[i].BpStrOffset; if (Pbpunit[i].BpFlag == IDS_HDTOUT_BPFLAG_FORMAT_STR) { PCmpStr = &ConsoleBuffer[LastIndex]; ConsoleBuffer[Index] = 0; } else { PCmpStr = IdsConsole->StatusStr; } if (LastBpmatched) { Bpmatched = AmdIdsSubStr (PCmpStr, Pbpstr); if (Bpmatched) { if (Pbpunit[i].AndFlag == 0) { // This is the last of matching string of an AND block, apply action here switch (Pbpunit[i].Action) { case HDTOUT_BP_ACTION_HALT: IdsConsoleOps->Print (DEBUG_PRINT_BREAKPOINT, (UINT32)(ConsoleBuffer + LastIndex), ( i << 16) | (UINT32) Index, IdsConsole); break; case HDTOUT_BP_ACTION_PRINTON: PrintCtrl = IDS_STATE_ON; IdsConsole->Header.PrintState = IDS_STATE_ON; break; case HDTOUT_BP_ACTION_PRINTOFF: if (IdsConsole->Header.PrintState != IDS_STATE_OFF) { IdsConsole->Header.PrintState = IDS_STATE_OFF; IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, (UINT32)Index, IdsConsole); } break; default: ASSERT (FALSE); } break; } } } if (Pbpunit[i].AndFlag == 1) { LastBpmatched = Bpmatched; } else { LastBpmatched = TRUE; } } } // // Store status fields // if (SaveStatus) { // Look for the start of the first word for (; LastIndex < Index; LastIndex++) { if ((ConsoleBuffer[LastIndex] > 32) && (ConsoleBuffer[LastIndex] < 127)) { break; } } if (LastIndex < Index) { // Match the first word in StatusStr SaveStatus = FALSE; j = LastIndex; for (i = 0; !SaveStatus && (IdsConsole->StatusStr[i] != 0); i++) { ArrayLength = 1; for (j = LastIndex; ConsoleBuffer[j] == IdsConsole->StatusStr[i]; j++) { i++; ArrayLength++; if ((j == (Index - 1)) || (ConsoleBuffer[j] == ' ')) { // Find the length of this entry ArrayIndex = i; for (; IdsConsole->StatusStr[i] != '\n'; i++) { ArrayLength++; } // Remove old entry if it does not fit if (ArrayLength != ((UINT32) Index - LastIndex)) { for (i++; IdsConsole->StatusStr[i] != 0; i++) { IdsConsole->StatusStr[i - ArrayLength] = IdsConsole->StatusStr[i]; } j = LastIndex; i = i - ArrayLength - 1; // Mark the end of string IdsConsole->StatusStr[i + ((UINT32) Index - LastIndex) + 1] = 0; } else { i = ArrayIndex - 2; } // Word match, exit for saving SaveStatus = TRUE; break; } } } // Copy string to StatusStr for (; j < Index; j++, i++) { IdsConsole->StatusStr[i] = ConsoleBuffer[j]; } if (!SaveStatus) { // Mark the end of string if not done so IdsConsole->StatusStr[i] = 0; } } } } } if (IdsConsole != NULL) { if (IdsConsole->Header.PrintState == IDS_STATE_OFF) { Index = 0; // Clear buffer if the data will not be printed out. } IdsConsole->Header.OutBufferIndex = (UINT16) Index; } else { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)ConsoleBuffer, (UINT32)Index, IdsConsole); } } } /** * * Exit function for IDS console Function. * * Restore debug register and Deallocate heap. * * @param[in,out] StdHeader The Pointer of AGESA Header * **/ VOID AmdIdsConsoleExit ( IN OUT AMD_CONFIG_PARAMS *StdHeader ) { IDS_CONSOLE *IdsConsole; UINTN IdsConsolePtr; IDS_CONSOLE_OPERATIONS *IdsConsoleOps; UINTN IdsConsoleOpsPtr; if (IsIdsConsoleEnabled (&IdsConsolePtr)) { GetIdsConsole (&IdsConsolePtr); IdsConsole = (IDS_CONSOLE *) IdsConsolePtr; GetIdsConsoleOperations (&IdsConsoleOpsPtr); IdsConsoleOps = (IDS_CONSOLE_OPERATIONS *) IdsConsoleOpsPtr; if (IdsConsole != NULL) { if (IdsConsole->Header.PrintState != IDS_STATE_OFF) { IdsConsoleOps->Print (DEBUG_PRINT_COMMAND, (UINT32)(IdsConsole->OutBuffer), IdsConsole->Header.OutBufferIndex, IdsConsole); } IdsConsoleOps->Print (DEBUG_PRINT_EXIT, (UINT32)IdsConsole, 0, IdsConsole); IdsConsoleOps->DestroyConsoleContext (IdsConsole); DestroyIdsConsole (IdsConsole, StdHeader); } } } /** * Check for CAR Corruption, the performance monitor number three programed to log the CAR Corruption. * Check to see if control register is enabled and then check the preformance counter and stop the system by executing * IDS_ERROR_TRAP if counter has any value other than zero. * * @param[in,out] StdHeader The Pointer of Standard Header. * * **/ VOID IdsCarCorruptionCheck ( IN OUT AMD_CONFIG_PARAMS *StdHeader ) { UINT64 Perf_Msr; LibAmdMsrRead (MSR_PERF_CONTROL3, (UINT64*)&Perf_Msr, StdHeader); if ((Perf_Msr & PERF_RESERVE_BIT_MASK) == PERF_CAR_CORRUPTION_EVENT) { LibAmdMsrRead (MSR_PERF_COUNTER3, (UINT64*)&Perf_Msr, StdHeader); if ((Perf_Msr != 0)) { IDS_ERROR_TRAP; } } }