/** * @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); }