blob: 95bb50941a125e20701d4bb1481a8ca5297fc59d [file] [log] [blame]
/**
* @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;
}
}
}