Ard,

The check for the runtime flag seems inconsistent.

Since the issue being addressed is use of SerialPortLib,
can't the mEfiAtRuntime flag be use around SerialPortLib
calls only.

Mike

> -----Original Message-----
> From: Ard Biesheuvel [mailto:ard.biesheu...@linaro.org]
> Sent: Thursday, February 22, 2018 8:28 AM
> To: edk2-devel@lists.01.org
> Cc: leif.lindh...@linaro.org; ler...@redhat.com; Gao,
> Liming <liming....@intel.com>; Kinney, Michael D
> <michael.d.kin...@intel.com>; af...@apple.com; Zeng,
> Star <star.z...@intel.com>; Ni, Ruiyu
> <ruiyu...@intel.com>; Ard Biesheuvel
> <ard.biesheu...@linaro.org>
> Subject: [PATCH edk2-platforms v2 1/2] MdePkg: introduce
> DxeRuntimeDebugLibSerialPort
> 
> Introduce a variant of BaseDebugLibSerialPort that
> behaves correctly with
> regards to the use of the serial port after
> ExitBootServices(). Also, it
> caches PCD values in the constructor so that no calls
> into PcdLib are
> made at runtime.
> 
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Ard Biesheuvel
> <ard.biesheu...@linaro.org>
> ---
>  MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c
> | 373 ++++++++++++++++++++
> 
> MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDe
> bugLibSerialPort.inf |  56 +++
> 
> MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDe
> bugLibSerialPort.uni |  21 ++
>  3 files changed, 450 insertions(+)
> 
> diff --git
> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c
> new file mode 100644
> index 000000000000..8579469029a1
> --- /dev/null
> +++
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c
> @@ -0,0 +1,373 @@
> +/** @file
> +  DXE runtime Debug library instance based on Serial
> Port library.
> +  It takes care not to call into SerialPortLib or
> PcdLib after
> +  ExitBootServices() has been called, to prevent
> touching hardware that is
> +  no longer owned by the firmware, or invoking
> protocols that are not safe
> +  for runtime (such as gEfiPcdProtocolGuid)
> +
> +  Copyright (c) 2006 - 2011, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2018, Linaro, Ltd. All rights
> reserved.<BR>
> +
> +  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 <Base.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DebugPrintErrorLevelLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/SerialPortLib.h>
> +
> +STATIC EFI_EVENT      mEfiExitBootServicesEvent;
> +STATIC BOOLEAN        mEfiAtRuntime;
> +
> +STATIC UINT8          mDebugClearMemoryValue;
> +STATIC UINT8          mDebugPropertyMask;
> +STATIC UINT32         mFixedDebugPrintErrorLevel;
> +
> +//
> +// Define the maximum debug and assert message length
> that this library supports
> +//
> +#define MAX_DEBUG_MESSAGE_LENGTH  0x100
> +
> +/**
> +  Set AtRuntime flag as TRUE after ExitBootServices.
> +
> +  @param[in]  Event   The Event that is being
> processed.
> +  @param[in]  Context The Event Context.
> +
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +ExitBootServicesEvent (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  mEfiAtRuntime = TRUE;
> +}
> +
> +/**
> +  The constructor function to initialize the Serial
> Port library and
> +  register a callback for the ExitBootServices event.
> +
> +  @param[in]  ImageHandle   The firmware allocated
> handle for the EFI image.
> +  @param[in]  SystemTable   A pointer to the EFI System
> Table.
> +
> +  @retval EFI_SUCCESS   The operation completed
> successfully.
> +  @retval other         Either the serial port failed
> to initialize or the
> +                        ExitBootServices event callback
> registration failed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +DxeRuntimeDebugLibSerialPortConstructor (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  EFI_STATUS    Status;
> +
> +  mDebugClearMemoryValue      = PcdGet8
> (PcdDebugClearMemoryValue);
> +  mDebugPropertyMask          = PcdGet8
> (PcdDebugPropertyMask);
> +  mFixedDebugPrintErrorLevel  = PcdGet32
> (PcdFixedDebugPrintErrorLevel);
> +
> +  Status = SerialPortInitialize ();
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  return SystemTable->BootServices->CreateEventEx
> (EVT_NOTIFY_SIGNAL,
> +                                      TPL_NOTIFY,
> ExitBootServicesEvent, NULL,
> +
> &gEfiEventExitBootServicesGuid,
> +
> &mEfiExitBootServicesEvent);
> +}
> +
> +/**
> +  If a runtime driver exits with an error, it must call
> this routine
> +  to free the allocated resource before the exiting.
> +
> +  @param[in]  ImageHandle   The firmware allocated
> handle for the EFI image.
> +  @param[in]  SystemTable   A pointer to the EFI System
> Table.
> +
> +  @retval     EFI_SUCCESS       The Runtime Driver Lib
> shutdown successfully.
> +  @retval     EFI_UNSUPPORTED   Runtime Driver lib was
> not initialized.
> +**/
> +EFI_STATUS
> +EFIAPI
> +DxeRuntimeDebugLibSerialPortDestructor (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  return SystemTable->BootServices->CloseEvent
> (mEfiExitBootServicesEvent);
> +}
> +
> +/**
> +  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().
> +
> +  @param  ErrorLevel  The error level of the debug
> message.
> +  @param  Format      Format string for the debug
> message to print.
> +  @param  ...         Variable argument list whose
> contents are accessed
> +                      based on the format string
> specified by Format.
> +
> +**/
> +VOID
> +EFIAPI
> +DebugPrint (
> +  IN  UINTN        ErrorLevel,
> +  IN  CONST CHAR8  *Format,
> +  ...
> +  )
> +{
> +  CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];
> +  VA_LIST  Marker;
> +
> +  if (mEfiAtRuntime) {
> +    return;
> +  }
> +
> +  ASSERT (Format != NULL);
> +
> +  //
> +  // Check driver debug mask value and global mask
> +  //
> +  if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
> +    return;
> +  }
> +
> +  //
> +  // Convert the DEBUG() message to an ASCII String
> +  //
> +  VA_START (Marker, Format);
> +  AsciiVSPrint (Buffer, sizeof (Buffer), Format,
> Marker);
> +  VA_END (Marker);
> +
> +  //
> +  // Send the print string to a Serial Port
> +  //
> +  SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen
> (Buffer));
> +}
> +
> +
> +/**
> +  Prints an assert message containing a filename, line
> number, and description.
> +  This may be followed by a breakpoint or a dead loop.
> +
> +  Print a message of the form "ASSERT
> <FileName>(<LineNumber>): <Description>\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 <FileName> string of
> "(NULL) Filename" is printed.
> +  If Description is NULL, then a <Description> string
> of "(NULL) Description" is
> +  printed.
> +
> +  @param  FileName     The pointer to the name of the
> source file that generated
> +                       the assert condition.
> +  @param  LineNumber   The line number in the source
> file that generated the
> +                       assert condition
> +  @param  Description  The pointer to the description
> of the assert condition.
> +
> +**/
> +VOID
> +EFIAPI
> +DebugAssert (
> +  IN CONST CHAR8  *FileName,
> +  IN UINTN        LineNumber,
> +  IN CONST CHAR8  *Description
> +  )
> +{
> +  CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];
> +
> +  if (!mEfiAtRuntime) {
> +    //
> +    // Generate the ASSERT() message in Ascii format
> +    //
> +    AsciiSPrint (Buffer, sizeof (Buffer), "ASSERT [%a]
> %a(%d): %a\n",
> +      gEfiCallerBaseName, FileName, LineNumber,
> Description);
> +
> +    //
> +    // Send the print string to the Console Output
> device
> +    //
> +    SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen
> (Buffer));
> +  }
> +
> +  //
> +  // Generate a Breakpoint, DeadLoop, or NOP based on
> PCD settings
> +  //
> +  if ((mDebugPropertyMask &
> DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
> +    CpuBreakpoint ();
> +  } else if ((mDebugPropertyMask &
> +              DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED)
> != 0) {
> +    CpuDeadLoop ();
> +  }
> +}
> +
> +
> +/**
> +  Fills a target buffer with PcdDebugClearMemoryValue,
> and returns the target
> +  buffer.
> +
> +  This function fills Length bytes of Buffer with the
> value specified by
> +  PcdDebugClearMemoryValue, and returns Buffer.
> +
> +  If Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1),
> then ASSERT().
> +
> +  @param   Buffer  The pointer to the target buffer to
> be filled with
> +                   PcdDebugClearMemoryValue.
> +  @param   Length  The number of bytes in Buffer to
> fill with
> +                   PcdDebugClearMemoryValue.
> +
> +  @return  Buffer  The pointer to the target buffer
> filled with
> +                   PcdDebugClearMemoryValue.
> +
> +**/
> +VOID *
> +EFIAPI
> +DebugClearMemory (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length
> +  )
> +{
> +  if (!mEfiAtRuntime) {
> +    ASSERT (Buffer != NULL);
> +    ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer +
> 1));
> +  }
> +
> +  return SetMem (Buffer, Length,
> mDebugClearMemoryValue);
> +}
> +
> +
> +/**
> +  Returns TRUE if ASSERT() macros are enabled.
> +
> +  This function returns TRUE if the
> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
> +  PcdDebugProperyMask is set.  Otherwise FALSE is
> returned.
> +
> +  @retval  TRUE    The
> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
> +                   PcdDebugProperyMask is set.
> +  @retval  FALSE   The
> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
> +                   PcdDebugProperyMask is clear.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +DebugAssertEnabled (
> +  VOID
> +  )
> +{
> +  return (BOOLEAN)((mDebugPropertyMask &
> +
> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
> +}
> +
> +
> +/**
> +  Returns TRUE if DEBUG() macros are enabled.
> +
> +  This function returns TRUE if the
> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
> +  PcdDebugProperyMask is set.  Otherwise FALSE is
> returned.
> +
> +  @retval  TRUE    The
> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
> +                   PcdDebugProperyMask is set.
> +  @retval  FALSE   The
> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
> +                   PcdDebugProperyMask is clear.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +DebugPrintEnabled (
> +  VOID
> +  )
> +{
> +  return (BOOLEAN)((mDebugPropertyMask &
> +                    DEBUG_PROPERTY_DEBUG_PRINT_ENABLED)
> != 0);
> +}
> +
> +
> +/**
> +  Returns TRUE if DEBUG_CODE() macros are enabled.
> +
> +  This function returns TRUE if the
> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
> +  PcdDebugProperyMask is set.  Otherwise FALSE is
> returned.
> +
> +  @retval  TRUE    The
> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
> +                   PcdDebugProperyMask is set.
> +  @retval  FALSE   The
> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
> +                   PcdDebugProperyMask is clear.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +DebugCodeEnabled (
> +  VOID
> +  )
> +{
> +  return (BOOLEAN)((mDebugPropertyMask &
> +                    DEBUG_PROPERTY_DEBUG_CODE_ENABLED)
> != 0);
> +}
> +
> +
> +/**
> +  Returns TRUE if DEBUG_CLEAR_MEMORY() macro is
> enabled.
> +
> +  This function returns TRUE if the
> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
> +  PcdDebugProperyMask is set.  Otherwise FALSE is
> returned.
> +
> +  @retval  TRUE    The
> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
> +                   PcdDebugProperyMask is set.
> +  @retval  FALSE   The
> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
> +                   PcdDebugProperyMask is clear.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +DebugClearMemoryEnabled (
> +  VOID
> +  )
> +{
> +  return (BOOLEAN)((mDebugPropertyMask &
> +
> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
> +}
> +
> +/**
> +  Returns TRUE if any one of the bit is set both in
> ErrorLevel and
> +  PcdFixedDebugPrintErrorLevel.
> +
> +  This function compares the bit mask of ErrorLevel and
> +  PcdFixedDebugPrintErrorLevel.
> +
> +  @retval  TRUE    Current ErrorLevel is supported.
> +  @retval  FALSE   Current ErrorLevel is not supported.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +DebugPrintLevelEnabled (
> +  IN  CONST UINTN        ErrorLevel
> +  )
> +{
> +  return (BOOLEAN)((ErrorLevel &
> mFixedDebugPrintErrorLevel) != 0);
> +}
> diff --git
> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.inf
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.inf
> new file mode 100644
> index 000000000000..d5e9d3f8dee7
> --- /dev/null
> +++
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.inf
> @@ -0,0 +1,56 @@
> +## @file
> +#  DXE runtime Debug library instance based on Serial
> Port library.
> +#  It takes care not to call into SerialPortLib or
> PcdLib after
> +#  ExitBootServices() has been called, to prevent
> touching hardware that is
> +#  no longer owned by the firmware, or invoking
> protocols that are not safe
> +#  for runtime (such as gEfiPcdProtocolGuid)
> +#
> +#  Copyright (c) 2006 - 2015, Intel Corporation. All
> rights reserved.<BR>
> +#  Copyright (c) 2018, Linaro, Ltd. All rights
> reserved.<BR>
> +#
> +#  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                    = 0x0001001A
> +  BASE_NAME                      =
> DxeRuntimeDebugLibSerialPort
> +  MODULE_UNI_FILE                =
> DxeRuntimeDebugLibSerialPort.uni
> +  FILE_GUID                      = 9D914E2F-7CCB-41DB-
> 8E74-9AFF8F3BBFBF
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  =
> DebugLib|DXE_RUNTIME_DRIVER
> +  CONSTRUCTOR                    =
> DxeRuntimeDebugLibSerialPortConstructor
> +  DESTRUCTOR                     =
> DxeRuntimeDebugLibSerialPortDestructor
> +
> +#
> +#  VALID_ARCHITECTURES           = AARCH64 ARM IA32 X64
> IPF EBC
> +#
> +
> +[Sources]
> +  DebugLib.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugPrintErrorLevelLib
> +  PcdLib
> +  PrintLib
> +  SerialPortLib
> +
> +[Guids]
> +  gEfiEventExitBootServicesGuid
> ## CONSUMES ## Event
> +
> +[Pcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue
> ## CONSUMES
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask
> ## CONSUMES
> +  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel
> ## CONSUMES
> diff --git
> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.uni
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.uni
> new file mode 100644
> index 000000000000..cd65515c4177
> --- /dev/null
> +++
> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime
> DebugLibSerialPort.uni
> @@ -0,0 +1,21 @@
> +// /** @file
> +// Instance of Debug Library based on Serial Port
> Library.
> +//
> +// It uses Print Library to produce formatted output
> strings to seiral port device.
> +//
> +// Copyright (c) 2006 - 2014, Intel Corporation. All
> rights reserved.<BR>
> +//
> +// 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.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US
> "Instance of Debug Library based on Serial Port Library"
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US
> "It uses Print Library to produce formatted output
> strings to a serial port device."
> +
> --
> 2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to