From bd7f65b61db7433cf6d773f168ca9dd6207ba65f Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 13:59:37 +0800 Subject: BroxtonPlatformPkg: Add PlatformDebugPei Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Console/PlatformDebugPei/PlatformDebugPei.c | 396 +++++++++++++++++++++ .../Console/PlatformDebugPei/PlatformDebugPei.inf | 58 +++ 2 files changed, 454 insertions(+) create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.inf diff --git a/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.c b/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.c new file mode 100644 index 0000000000..41ac9c94c5 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.c @@ -0,0 +1,396 @@ +/** @file + Platform PEI Debug Driver. + + Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format and the + associated variable argument list to the debug output device. + If Format is NULL, then ASSERT(). + If the length of the message string specificed by Format is larger than the maximum allowable + record length, then directly return and not print it. + + @param[in] ErrorLevel The error level of the debug message. + @param[in] Format Format string for the debug message to print. + @param[in] Marker Variable argument list whose contents are accessed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +PeiDebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + IN VA_LIST VaListMarker + ) +{ + UINT64 Buffer[(MAX_DEBUG_MESSAGE_LENGTH / sizeof (UINT64)) + 1]; + EFI_DEBUG_INFO *DebugInfo; + UINTN TotalSize; + BASE_LIST BaseListMarker; + CHAR8 *FormatString; + BOOLEAN Long; + + // + // Compute the total size of the record. + // Note that the passing-in format string and variable parameters will be constructed to + // the following layout: + // + // Buffer->|------------------------| + // | Padding | 4 bytes + // DebugInfo->|------------------------| + // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO) + // BaseListMarker->|------------------------| + // | ... | + // | variable arguments | 12 * sizeof (UINT64) + // | ... | + // |------------------------| + // | Format String | + // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer) + // + TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format); + + // + // If the TotalSize is larger than the maximum record size, then return + // + if (TotalSize > sizeof (Buffer)) { + return; + } + + // + // Fill in EFI_DEBUG_INFO + // + // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is + // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause + // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO)) + // just makes address of BaseListMarker, which follows DebugInfo, 64-bit aligned. + // + DebugInfo = (EFI_DEBUG_INFO *) (Buffer) + 1; + DebugInfo->ErrorLevel = (UINT32) ErrorLevel; + BaseListMarker = (BASE_LIST) (DebugInfo + 1); + FormatString = (CHAR8 *) ((UINT64 *) (DebugInfo + 1) + 12); + + // + // Copy the Format string into the record + // + AsciiStrCpyS (FormatString, sizeof (Buffer) - 4 - (sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64)), Format); + + // + // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments + // of format in DEBUG string, which is followed by the DEBUG format string. + // Here we will process the variable arguments and pack them in this area. + // + for (; *Format != '\0'; Format++) { + // + // Only format with prefix % is processed. + // + if (*Format != '%') { + continue; + } + Long = FALSE; + // + // Parse Flags and Width + // + for (Format++; TRUE; Format++) { + if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') { + // + // These characters in format field are omitted. + // + continue; + } + if (*Format >= '0' && *Format <= '9') { + // + // These characters in format field are omitted. + // + continue; + } + if (*Format == 'L' || *Format == 'l') { + // + // 'L" or "l" in format field means the number being printed is a UINT64 + // + Long = TRUE; + continue; + } + if (*Format == '*') { + // + // '*' in format field means the precision of the field is specified by + // a UINTN argument in the argument list. + // + BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN); + continue; + } + if (*Format == '\0') { + // + // Make no output if Format string terminates unexpectedly when + // looking up for flag, width, precision and type. + // + Format--; + } + // + // When valid argument type detected or format string terminates unexpectedly, + // the inner loop is done. + // + break; + } + + // + // Pack variable arguments into the storage area following EFI_DEBUG_INFO. + // + if ((*Format == 'p') && (sizeof (VOID *) > 4)) { + Long = TRUE; + } + if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd') { + if (Long) { + BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64); + } else { + BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int); + } + } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') { + BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *); + } else if (*Format == 'c') { + BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN); + } else if (*Format == 'r') { + BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS); + } + + // + // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT() + // This indicates that the DEBUG() macro is passing in more argument than can be handled by + // the EFI_DEBUG_INFO record + // + ASSERT ((CHAR8 *) BaseListMarker <= FormatString); + + // + // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return + // + if ((CHAR8 *) BaseListMarker > FormatString) { + VA_END (VaListMarker); + return; + } + } + + // + // Send the DebugInfo record + // + REPORT_STATUS_CODE_EX ( + EFI_DEBUG_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED), + 0, + NULL, + &gEfiStatusCodeDataTypeDebugGuid, + DebugInfo, + TotalSize + ); +} + + +/** + Prints an assert message containing a file name, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recursion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) File name" is printed. + If Description is NULL, then a string of "(NULL) Description" is printed. + + @param[in] FileName Pointer to the name of the source file that generated the assert condition. + @param[in] LineNumber The line number in the source file that generated the assert condition + @param[in] Description Pointer to the description of the assert condition. + @param[in] DebugPropertyMask PropertyMask to the description of the assert. + +**/ +VOID +EFIAPI +PeiDebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description, + IN UINT8 DebugPropertyMask + ) +{ + UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)]; + EFI_DEBUG_ASSERT_DATA *AssertData; + UINTN HeaderSize; + UINTN TotalSize; + CHAR8 *Temp; + UINTN FileNameSize; + UINTN DescriptionSize; + + // + // Get string size + // + HeaderSize = sizeof (EFI_DEBUG_ASSERT_DATA); + FileNameSize = AsciiStrSize (FileName); + DescriptionSize = AsciiStrSize (Description); + + // + // Make sure it will all fit in the passed in buffer. + // + if (HeaderSize + FileNameSize + DescriptionSize > sizeof (Buffer)) { + // + // FileName + Description is too long to be filled into buffer. + // + if (HeaderSize + FileNameSize < sizeof (Buffer)) { + // + // Description has enough buffer to be truncated. + // + DescriptionSize = sizeof (Buffer) - HeaderSize - FileNameSize; + } else { + // + // FileName is too long to be filled into buffer. + // FileName will be truncated. Reserved one byte for Description NULL terminator. + // + DescriptionSize = 1; + FileNameSize = sizeof (Buffer) - HeaderSize - DescriptionSize; + } + } + + // + // Fill in EFI_DEBUG_ASSERT_DATA + // + AssertData = (EFI_DEBUG_ASSERT_DATA *) Buffer; + AssertData->LineNumber = (UINT32) LineNumber; + TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA); + + // + // Copy Ascii FileName including NULL terminator. + // + Temp = CopyMem (AssertData + 1, FileName, FileNameSize); + Temp[FileNameSize - 1] = 0; + TotalSize += FileNameSize; + + // + // Copy Ascii Description include NULL terminator. + // + Temp = CopyMem (Temp + FileNameSize, Description, DescriptionSize); + Temp[DescriptionSize - 1] = 0; + TotalSize += DescriptionSize; + + REPORT_STATUS_CODE_EX ( + (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED), + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE), + 0, + NULL, + NULL, + AssertData, + TotalSize + ); + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((DebugPropertyMask & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { + CpuBreakpoint (); + } else if ((DebugPropertyMask & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { + CpuDeadLoop (); + } +} + +CHAR8 mGdtTable[0x40]; + +DEBUG_SERVICE_PPI mDebugServicePpi = { + PeiDebugPrint, + PeiDebugAssert +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiList[] = { + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gDebugServicePpiGuid, + (VOID *) &mDebugServicePpi + } +}; + + +/** + Main entry + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Pointer to PEI Services table. + + @retval EFI_SUCCESS Install function successfully. + +**/ +EFI_STATUS +EFIAPI +PeiDebugInstanceEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor; + EFI_STATUS Status= EFI_SUCCESS; + BOOLEAN ImageInMemory = FALSE; + + Status = (*PeiServices)->RegisterForShadow (FileHandle); + + if (Status == EFI_ALREADY_STARTED) { + ImageInMemory = TRUE; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + + if (!ImageInMemory) { + // + // Register for a callback once memory has been initialized. + // + Status = PeiServicesInstallPpi (&mPpiList[0]); + ASSERT_EFI_ERROR (Status); + } else { + + // + // locate the SEC platform information PPI + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gDebugServicePpiGuid, + 0, + &PeiPpiDescriptor, + NULL + ); + if (Status == EFI_SUCCESS) { + // + // Reinstall the StatusCode PPI + // + Status = (**PeiServices).ReInstallPpi ( + PeiServices, + PeiPpiDescriptor, + &mPpiList[0] + ); + } + } + + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.inf b/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.inf new file mode 100644 index 0000000000..50e6b49217 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Console/PlatformDebugPei/PlatformDebugPei.inf @@ -0,0 +1,58 @@ +## @file +# Platform PEI Debug Driver module. +# +# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = PeiDebugInstance + FILE_GUID = bda39d3a-451b-4350-8266-81ab10fa0526 + VERSION_STRING = 1.0 + MODULE_TYPE = PEIM + ENTRY_POINT = PeiDebugInstanceEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[LibraryClasses] + PeimEntryPoint + PcdLib + ReportStatusCodeLib + BaseMemoryLib + BaseLib + DebugPrintErrorLevelLib + PeiServicesLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + BroxtonPlatformPkg/PlatformPkg.dec + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask + +[Sources] + PlatformDebugPei.c + +[Ppis] + gDebugServicePpiGuid ## PRODUCES + +[Guids] + gEfiStatusCodeDataTypeDebugGuid ## CONSUMES + +[Depex] + TRUE -- cgit v1.2.3