| /** |
| * @file |
| * |
| * AMD Integrated Debug Print Routines |
| * |
| * Contains all functions related to IDS Debug Print |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: AGESA |
| * @e sub-project: IDS |
| * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ |
| */ |
| /***************************************************************************** |
| * Copyright (c) 2008 - 2012, 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 "IdsDebugPrint.h" |
| #include "Filecode.h" |
| CODE_GROUP (G1_PEICC) |
| RDATA_GROUP (G1_PEICC) |
| |
| #define FILECODE PROC_IDS_DEBUG_IDSDEBUGPRINT_FILECODE |
| |
| // |
| // Also support coding convention rules for var arg macros |
| // |
| #define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) |
| 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 |
| |
| #define MAX_LOCAL_BUFFER_SIZE 512 |
| #define BUFFER_OVERFLOW 0xFFFF |
| |
| /** |
| * Check If any print service is enabled. |
| * |
| * @param[in] DebugPrintList The Pointer to print service list |
| * |
| * @retval TRUE At least on print service is enabled |
| * @retval FALSE All print service is disabled |
| * |
| **/ |
| STATIC BOOLEAN |
| AmdIdsDebugPrintCheckSupportAll ( |
| IN IDS_DEBUG_PRINT **DebugPrintList |
| ) |
| { |
| BOOLEAN IsSupported; |
| UINTN i; |
| IsSupported = FALSE; |
| for (i = 0; DebugPrintList[i] != NULL; i++) { |
| if (DebugPrintList[i]->support ()) { |
| IsSupported = TRUE; |
| } |
| } |
| return IsSupported; |
| } |
| |
| /** |
| * 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' }; |
| extern CONST IDS_DEBUG_PRINT* ROMDATA IdsDebugPrint[]; |
| |
| /** |
| * |
| * @param[in,out] Value - Hex value to convert to a string in Buffer. |
| * |
| * |
| */ |
| VOID |
| GetDebugPrintList ( |
| IN OUT CONST IDS_DEBUG_PRINT ***pIdsDebugPrintListPtr |
| ) |
| { |
| *pIdsDebugPrintListPtr = &IdsDebugPrint[0]; |
| } |
| |
| /** |
| * |
| * @param[in,out] 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. |
| * @param[in,out] BufferSize - Size of input buffer |
| * |
| * @retval Number of characters printed. |
| **/ |
| |
| STATIC UINTN |
| ValueToHexStr ( |
| IN OUT CHAR8 *Buffer, |
| IN UINT64 Value, |
| IN UINTN Flags, |
| IN UINTN Width, |
| IN OUT UINTN *BufferSize |
| ) |
| { |
| 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) { |
| (*BufferSize)--; |
| if (*BufferSize == 0) { |
| return BUFFER_OVERFLOW; |
| } |
| *(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. |
| * @param[in,out] BufferSize Size of input buffer |
| * |
| * @retval Number of characters printed. |
| * |
| **/ |
| |
| STATIC UINTN |
| ValueToString ( |
| IN OUT CHAR8 *Buffer, |
| IN INT32 Value, |
| IN UINTN Flags, |
| IN OUT UINTN *BufferSize |
| ) |
| { |
| CHAR8 TempBuffer[30]; |
| CHAR8 *TempStr; |
| CHAR8 *BufferPtr; |
| UINTN Count; |
| UINTN Remainder; |
| |
| ASSERT (*BufferSize); |
| TempStr = TempBuffer; |
| BufferPtr = Buffer; |
| Count = 0; |
| |
| if (Value < 0) { |
| (*BufferSize)--; |
| if (*BufferSize == 0) { |
| return BUFFER_OVERFLOW; |
| } |
| *(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) { |
| (*BufferSize)--; |
| if (*BufferSize == 0) { |
| return BUFFER_OVERFLOW; |
| } |
| *(BufferPtr++) = *(--TempStr); |
| } |
| |
| *BufferPtr = 0; |
| return Count; |
| } |
| |
| /** |
| * Worker function for print string to buffer |
| * |
| * @param[in] Flag - filter flag |
| * @param[in] *Format - format string |
| * @param[in] Marker - Variable parameter |
| * @param[in] Buffer - Point to input buffer |
| * @param[in] BufferSize - Buffer size |
| * @param[out] OutputStringLen - output string length, include '\0' at the end |
| * |
| * @retval IDS_DEBUG_PRINT_SUCCESS succeed |
| * @retval IDS_DEBUG_PRINT_BUFFER_OVERFLOW input buffer overflow |
| **/ |
| STATIC IDS_DEBUG_PRINT_STATUS |
| AmdIdsDebugPrintWorker ( |
| IN CONST CHAR8 *Format, |
| IN VA_LIST Marker, |
| IN CHAR8 *Buffer, |
| IN UINTN BufferSize, |
| OUT UINTN *OutputStringLen |
| ) |
| { |
| UINTN Index; |
| UINTN Length; |
| UINTN Flags; |
| UINTN Width; |
| UINT64 Value; |
| CHAR8 *AsciiStr; |
| |
| //Init the default Value |
| Index = 0; |
| // |
| // Process format string |
| // |
| for (; (*Format != '\0') && (BufferSize > 0); Format++) { |
| if (*Format != '%') { |
| Buffer[Index++] = *Format; |
| BufferSize--; |
| } else { |
| Format = GetFlagsAndWidth ((CHAR8 *)Format, &Flags, &Width, &Marker); |
| switch (*Format) { |
| case 'X': |
| Flags |= PREFIX_ZERO; |
| Width = sizeof (UINT64) * 2; |
| // fall through |
| case 'x': |
| if ((Flags & LONG_TYPE) == LONG_TYPE) { |
| Value = VA_ARG (Marker, UINT64); |
| } else { |
| Value = VA_ARG (Marker, UINTN); |
| } |
| Length = ValueToHexStr (&Buffer[Index], Value, Flags, Width, &BufferSize); |
| if (Length != BUFFER_OVERFLOW) { |
| Index += Length; |
| } else { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| break; |
| |
| case 'd': |
| Value = (UINTN)VA_ARG (Marker, UINT32); |
| Length = ValueToString (&Buffer[Index], (UINT32)Value, Flags, &BufferSize); |
| if (Length != BUFFER_OVERFLOW) { |
| Index += Length; |
| } else { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| |
| break; |
| |
| case 's': |
| case 'S': |
| AsciiStr = (CHAR8 *)VA_ARG (Marker, CHAR8 *); |
| while (*AsciiStr != '\0') { |
| BufferSize--; |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| Buffer[Index++] = *AsciiStr++; |
| } |
| break; |
| |
| case 'c': |
| BufferSize--; |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| Buffer[Index++] = (CHAR8)VA_ARG (Marker, UINTN); |
| break; |
| |
| case 'v': |
| ASSERT (FALSE); // %v is no longer supported |
| break; |
| |
| case '%': |
| BufferSize--; |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| Buffer[Index++] = *Format; |
| break; |
| |
| default: |
| // |
| // if the type is unknown print it to the screen |
| // |
| BufferSize--; |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| Buffer[Index++] = '%'; |
| |
| BufferSize--; |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| Buffer[Index++] = *Format; |
| break; |
| } |
| } |
| } |
| if (BufferSize == 0) { |
| return IDS_DEBUG_PRINT_BUFFER_OVERFLOW; |
| } |
| //Mark the end of word |
| Buffer[Index] = 0; |
| *OutputStringLen = Index; |
| return IDS_DEBUG_PRINT_SUCCESS; |
| } |
| |
| |
| /** |
| * Insert Overflow warning to the tail of output |
| * |
| * @param[in] Buffer - Point to input buffer |
| * @param[in] BufferSize - Buffer size |
| * |
| **/ |
| STATIC VOID |
| InsertOverflowWarningMessage ( |
| IN CHAR8 *Buffer, |
| IN UINTN BufferSize |
| ) |
| { |
| CHAR8 *Destination; |
| CHAR8 WarningString[] = "\n#BUFFER OVERFLOW#\n"; |
| AMD_CONFIG_PARAMS StdHeader; |
| |
| Destination = Buffer + BufferSize - sizeof (WarningString); |
| LibAmdMemCopy (Destination, WarningString, sizeof (WarningString), &StdHeader); |
| } |
| |
| /** |
| * Process debug string |
| * |
| * @param[in] Flag - filter flag |
| * @param[in] *Format - format string |
| * @param[in] Marker - Variable parameter |
| * |
| **/ |
| STATIC VOID |
| AmdIdsDebugPrintProcess ( |
| IN UINT64 Flag, |
| IN CONST CHAR8 *Format, |
| IN VA_LIST Marker |
| ) |
| { |
| UINT64 Filter; |
| CHAR8 LocalBuffer[MAX_LOCAL_BUFFER_SIZE]; |
| UINTN OutPutStringLen; |
| IDS_DEBUG_PRINT **DebugPrintList; |
| IDS_DEBUG_PRINT_PRIVATE_DATA debugPrintPrivate; |
| UINT8 i; |
| |
| |
| GetDebugPrintList ((CONST IDS_DEBUG_PRINT ***)&DebugPrintList); |
| if (AmdIdsDebugPrintCheckSupportAll (DebugPrintList)) { |
| if (AmdIdsDebugPrintWorker (Format, Marker, &LocalBuffer[0], sizeof (LocalBuffer), &OutPutStringLen) == IDS_DEBUG_PRINT_BUFFER_OVERFLOW) { |
| InsertOverflowWarningMessage (&LocalBuffer[0], sizeof (LocalBuffer)); |
| OutPutStringLen = sizeof (LocalBuffer); |
| } |
| |
| //init input |
| debugPrintPrivate.saveContext = FALSE; |
| |
| for (i = 0; DebugPrintList[i] != NULL; i++) { |
| if (DebugPrintList[i]->support ()) { |
| Filter = IDS_DEBUG_PRINT_MASK; |
| //Get Customize filter (Option) |
| DebugPrintList[i]->customfilter (&Filter); |
| if (Flag & Filter) { |
| //Init Private Date (Option) |
| DebugPrintList[i]->InitPrivateData (Flag, &debugPrintPrivate); |
| //Print Physical Layer |
| DebugPrintList[i]->print (&LocalBuffer[0], OutPutStringLen, &debugPrintPrivate); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Prints string to debug host like printf in C |
| * |
| * @param[in] Flag - filter flag |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrint ( |
| IN UINT64 Flag, |
| IN CONST CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (Flag, Format, Marker); |
| VA_END (Marker); |
| } |
| |
| /** |
| * Prints memory debug strings |
| * |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrintMem ( |
| IN CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (MEM_FLOW, Format, Marker); |
| VA_END (Marker); |
| } |
| |
| /** |
| * Prints CPU debug strings |
| * |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrintCpu ( |
| IN CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (CPU_TRACE, Format, Marker); |
| VA_END (Marker); |
| } |
| |
| |
| /** |
| * Prints HT debug strings |
| * |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrintHt ( |
| IN CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (HT_TRACE, Format, Marker); |
| VA_END (Marker); |
| } |
| |
| |
| /** |
| * Prints GNB debug strings |
| * |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrintGnb ( |
| IN CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (GNB_TRACE, Format, Marker); |
| VA_END (Marker); |
| } |
| |
| /** |
| * Prints debug strings in any condition |
| * |
| * @param[in] *Format - format string |
| * @param[in] ... Variable parameter |
| * |
| **/ |
| VOID |
| AmdIdsDebugPrintAll ( |
| IN CHAR8 *Format, |
| IN ... |
| ) |
| { |
| VA_LIST Marker; |
| VA_START (Marker, Format); //init marker to 1st dynamic parameters. |
| AmdIdsDebugPrintProcess (TRACE_MASK_ALL, Format, Marker); |
| VA_END (Marker); |
| } |
| |