[edk2-devel] [edk2-platforms][PATCH v2 04/32] AmperePlatformPkg: Add FailSafe and WDT support

Nhi Pham via groups.io nhi=os.amperecomputing.com at groups.io
Tue Jun 15 16:47:29 UTC 2021


Hi Leif,

On 6/5/21 06:12, Leif Lindholm wrote:
> On Wed, May 26, 2021 at 17:06:56 +0700, Nhi Pham wrote:
>> The FailSafeDxe driver reverts the system's configuration to known good
>> values if the system fails to boot up multiple times. It also implements
>> the Watchdog Timer Architectural Protocol to reset the system if it
>> hangs.
>>
>> By default, when system starts, it configures the secure watchdog timer
>> with a default value of 5 minutes. If the system boots up cleanly to the
>> considered good stage, the counter is cleared as it indicates FailSafe
>> monitor (ATF) that has booted up successfully. If the timer expires, it
>> is considered a failed boot and system is rebooted.
>>
>> Cc: Thang Nguyen <thang at os.amperecomputing.com>
>> Cc: Chuong Tran <chuong at os.amperecomputing.com>
>> Cc: Phong Vo <phong at os.amperecomputing.com>
>> Cc: Leif Lindholm <leif at nuviainc.com>
>> Cc: Michael D Kinney <michael.d.kinney at intel.com>
>> Cc: Ard Biesheuvel <ardb+tianocore at kernel.org>
>> Cc: Nate DeSimone <nathaniel.l.desimone at intel.com>
>>
>> Signed-off-by: Nhi Pham <nhi at os.amperecomputing.com>
>> ---
>>   Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc                  |   1 -
>>   Platform/Ampere/JadePkg/Jade.dsc                                      |   9 +
>>   Platform/Ampere/JadePkg/Jade.fdf                                      |   6 +-
>>   Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf |  54 +++
>>   Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafe.h      |  20 ++
>>   Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.h      |  29 ++
>>   Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.c   | 184 ++++++++++
>>   Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.c      | 357 ++++++++++++++++++++
>>   8 files changed, 658 insertions(+), 2 deletions(-)
>>
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> index 0332473b59b0..6a6f72e995af 100755
>> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> @@ -585,7 +585,6 @@ [Components.common]
>>     # Timer
>>     #
>>     ArmPkg/Drivers/TimerDxe/TimerDxe.inf
>> -  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> It's not clear from the commit message why this should happen.
>
>>   
>>     #
>>     # ARM GIC Dxe
>> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
>> index f68af24a0d78..f92855af99ab 100755
>> --- a/Platform/Ampere/JadePkg/Jade.dsc
>> +++ b/Platform/Ampere/JadePkg/Jade.dsc
>> @@ -75,6 +75,11 @@ [LibraryClasses]
>>     #
>>     RealTimeClockLib|EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
>>   
>> +  #
>> +  # Library for FailSafe support
>> +  #
>> +  FailSafeLib|Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.inf
>> +
>>   ################################################################################
>>   #
>>   # Specific Platform Pcds
>> @@ -98,3 +103,7 @@ [PcdsFixedAtBuild.common]
>>   #
>>   ################################################################################
>>   [Components.common]
>> +  #
>> +  # FailSafe and Watchdog Timer
>> +  #
>> +  Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
>> index 905289844378..80a86d7c1156 100755
>> --- a/Platform/Ampere/JadePkg/Jade.fdf
>> +++ b/Platform/Ampere/JadePkg/Jade.fdf
>> @@ -185,7 +185,11 @@ [FV.FvMain]
>>     # Timer
>>     #
>>     INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
>> -  INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> It's not clear from the commit message why this should happen.

The Watchdog protocol which is implemented in this Failsafe driver will 
replace the WatchdogTimer.inf. I will update the commit message to 
clarify this.

Best regards,

Nhi

>
> /
>      Leif
>
>> +
>> +  #
>> +  # FailSafe and Watchdog Timer
>> +  #
>> +  INF Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>>   
>>     #
>>     # ARM GIC Dxe
>> diff --git a/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>> new file mode 100755
>> index 000000000000..60de10c95c85
>> --- /dev/null
>> +++ b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>> @@ -0,0 +1,54 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = FailSafeDxe
>> +  FILE_GUID                      = 7BC4F970-B1CF-11E6-80F5-76304DEC7EB7
>> +  MODULE_TYPE                    = DXE_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  ENTRY_POINT                    = FailSafeDxeEntryPoint
>> +
>> +[Sources]
>> +  FailSafe.h
>> +  FailSafeDxe.c
>> +  Watchdog.c
>> +  Watchdog.h
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  EmbeddedPkg/EmbeddedPkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  MdePkg/MdePkg.dec
>> +  Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec
>> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +
>> +[LibraryClasses]
>> +  ArmSmcLib
>> +  DebugLib
>> +  FailSafeLib
>> +  NVParamLib
>> +  PcdLib
>> +  TimerLib
>> +  UefiBootServicesTableLib
>> +  UefiDriverEntryPoint
>> +  UefiLib
>> +  UefiRuntimeServicesTableLib
>> +
>> +[Pcd]
>> +  gArmTokenSpaceGuid.PcdGenericWatchdogControlBase
>> +  gArmTokenSpaceGuid.PcdGenericWatchdogEl2IntrNum
>> +
>> +[Protocols]
>> +  gEfiWatchdogTimerArchProtocolGuid             ## PRODUCES
>> +  gHardwareInterrupt2ProtocolGuid               ## CONSUMES
>> +
>> +[Depex]
>> +  gHardwareInterrupt2ProtocolGuid
>> diff --git a/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafe.h b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafe.h
>> new file mode 100644
>> index 000000000000..8bf3a98f1d8e
>> --- /dev/null
>> +++ b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafe.h
>> @@ -0,0 +1,20 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef FAILSAFE_H_
>> +#define FAILSAFE_H_
>> +
>> +#include <Uefi.h>
>> +
>> +BOOLEAN
>> +EFIAPI
>> +IsFailSafeOff (
>> +  VOID
>> +  );
>> +
>> +#endif /* FAILSAFE_H_ */
>> diff --git a/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.h b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.h
>> new file mode 100755
>> index 000000000000..6c9106fdbea5
>> --- /dev/null
>> +++ b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.h
>> @@ -0,0 +1,29 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef GENERIC_WATCHDOG_H_
>> +#define GENERIC_WATCHDOG_H_
>> +
>> +#include <Protocol/WatchdogTimer.h>
>> +
>> +/* The number of 100ns periods (the unit of time passed to these functions)
>> +   in a second */
>> +#define TIME_UNITS_PER_SECOND           10000000
>> +
>> +/**
>> +  The function to install Watchdog timer protocol to the system
>> +
>> +  @retval  Return         EFI_SUCCESS if install Watchdog timer protocol successfully.
>> + **/
>> +EFI_STATUS
>> +EFIAPI
>> +WatchdogTimerInstallProtocol (
>> +  EFI_WATCHDOG_TIMER_ARCH_PROTOCOL **WatchdogTimerProtocol
>> +  );
>> +
>> +#endif /* GENERIC_WATCHDOG_H_ */
>> diff --git a/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.c b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.c
>> new file mode 100644
>> index 000000000000..1b8978b12ea7
>> --- /dev/null
>> +++ b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/FailSafeDxe.c
>> @@ -0,0 +1,184 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Uefi.h>
>> +
>> +#include <Guid/EventGroup.h>
>> +#include <Library/ArmSmcLib.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/FailSafeLib.h>
>> +#include <Library/NVParamLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/UefiRuntimeServicesTableLib.h>
>> +
>> +#include "FailSafe.h"
>> +#include "Watchdog.h"
>> +
>> +STATIC UINTN                            gWatchdogOSTimeout;
>> +STATIC BOOLEAN                          gFailSafeOff;
>> +STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FailSafeTestBootFailure (
>> +  VOID
>> +  );
>> +
>> +STATIC VOID
>> +FailSafeTurnOff (
>> +  VOID
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +
>> +  if (IsFailSafeOff ()) {
>> +    return;
>> +  }
>> +
>> +  Status = FailSafeBootSuccessfully ();
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  gFailSafeOff = TRUE;
>> +
>> +  /* Disable Watchdog timer */
>> +  gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, 0);
>> +}
>> +
>> +BOOLEAN
>> +EFIAPI
>> +IsFailSafeOff (
>> +  VOID
>> +  )
>> +{
>> +  return gFailSafeOff;
>> +}
>> +
>> +/**
>> +  The function to disable Watchdog timer when enter Setup screen
>> + **/
>> +VOID
>> +WdtTimerEnterSetupScreenCallback (
>> +  IN EFI_EVENT Event,
>> +  IN VOID      *Context
>> +  )
>> +{
>> +  /* Make sure FailSafe is turned off */
>> +  FailSafeTurnOff ();
>> +}
>> +
>> +/**
>> +  The function to refresh Watchdog timer in the event before booting
>> + **/
>> +VOID
>> +WdtTimerBeforeBootCallback (
>> +  IN EFI_EVENT Event,
>> +  IN VOID      *Context
>> +  )
>> +{
>> +  /*
>> +   * At this point, the system is considered boot successfully to BIOS
>> +   */
>> +  FailSafeTurnOff ();
>> +
>> +  /*
>> +   * It is BIOS's responsibility to setup Watchdog when load an EFI application
>> +   * after this step
>> +   */
>> +}
>> +
>> +/**
>> +  The function to refresh Watchdog timer in the event before exiting boot services
>> + **/
>> +VOID
>> +WdtTimerExitBootServiceCallback (
>> +  IN EFI_EVENT Event,
>> +  IN VOID      *Context
>> +  )
>> +{
>> +
>> +  /* Enable Watchdog timer for OS booting */
>> +  if (gWatchdogOSTimeout != 0) {
>> +    gWatchdogTimer->SetTimerPeriod (
>> +                      gWatchdogTimer,
>> +                      gWatchdogOSTimeout * TIME_UNITS_PER_SECOND
>> +                      );
>> +  } else {
>> +    /* Disable Watchdog timer */
>> +    gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, 0);
>> +  }
>> +}
>> +
>> +/**
>> +  This function is a hook called when user loads the manufacturing
>> +  or optimal defaults.
>> +
>> +  @param Defaults : (NVRAM_VARIABLE *)optimal or manufacturing
>> +  @Data           : Messagebox
>> +
>> +  @retval VOID
>> +**/
>> +VOID
>> +LoadNVRAMDefaultConfig (
>> +  IN VOID  *Defaults,
>> +  IN UINTN Data
>> +  )
>> +{
>> +  NVParamClrAll ();
>> +}
>> +
>> +/**
>> +  Main entry for this driver.
>> +
>> +  @param ImageHandle     Image handle this driver.
>> +  @param SystemTable     Pointer to SystemTable.
>> +
>> +  @retval EFI_SUCESS     This function always complete successfully.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FailSafeDxeEntryPoint (
>> +  IN EFI_HANDLE       ImageHandle,
>> +  IN EFI_SYSTEM_TABLE *SystemTable
>> +  )
>> +{
>> +  EFI_EVENT  ExitBootServicesEvent;
>> +  EFI_STATUS Status;
>> +
>> +  gFailSafeOff = FALSE;
>> +
>> +  FailSafeTestBootFailure ();
>> +
>> +  /* We need to setup non secure Watchdog to ensure that the system will
>> +   * boot to OS successfully.
>> +   *
>> +   * The BIOS doesn't handle Watchdog interrupt so we expect WS1 asserted EL3
>> +   * when Watchdog timeout triggered
>> +   */
>> +
>> +  Status = WatchdogTimerInstallProtocol (&gWatchdogTimer);
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  // FIXME: We should register a callback function before entering to Setup screen
>> +  // rather than always call it at DXE phase.
>> +  FailSafeTurnOff ();
>> +
>> +  /* Register event before exit boot services */
>> +  Status = gBS->CreateEvent (
>> +                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
>> +                  TPL_NOTIFY,
>> +                  WdtTimerExitBootServiceCallback,
>> +                  NULL,
>> +                  &ExitBootServicesEvent
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  return Status;
>> +}
>> diff --git a/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.c b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.c
>> new file mode 100644
>> index 000000000000..34329d04206a
>> --- /dev/null
>> +++ b/Platform/Ampere/AmperePlatformPkg/Drivers/FailSafeDxe/Watchdog.c
>> @@ -0,0 +1,357 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Library/ArmGenericTimerCounterLib.h>
>> +#include <Library/ArmLib.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/IoLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeServicesTableLib.h>
>> +#include <Protocol/HardwareInterrupt2.h>
>> +
>> +#include "FailSafe.h"
>> +#include "Watchdog.h"
>> +
>> +/* Watchdog timer controller registers */
>> +#define WDT_CTRL_BASE_REG                     FixedPcdGet64 (PcdGenericWatchdogControlBase)
>> +#define WDT_CTRL_WCS_OFF                      0x0
>> +#define WDT_CTRL_WCS_ENABLE_MASK              0x1
>> +#define WDT_CTRL_WOR_OFF                      0x8
>> +#define WDT_CTRL_WCV_OFF                      0x10
>> +#define WS0_INTERRUPT_SOURCE                  FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum)
>> +
>> +STATIC UINT64                           mNumTimerTicks;
>> +STATIC EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol;
>> +BOOLEAN                                 mInterruptWS0Enabled;
>> +
>> +STATIC
>> +VOID
>> +WatchdogTimerWriteOffsetRegister (
>> +  UINT32 Value
>> +  )
>> +{
>> +  MmioWrite32 (WDT_CTRL_BASE_REG + WDT_CTRL_WOR_OFF, Value);
>> +}
>> +
>> +STATIC
>> +VOID
>> +WatchdogTimerWriteCompareRegister (
>> +  UINT64 Value
>> +  )
>> +{
>> +  MmioWrite64 (WDT_CTRL_BASE_REG + WDT_CTRL_WCV_OFF, Value);
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +WatchdogTimerEnable (
>> +  IN BOOLEAN Enable
>> +  )
>> +{
>> +  UINT32 Val =  MmioRead32 ((UINTN)(WDT_CTRL_BASE_REG + WDT_CTRL_WCS_OFF));
>> +
>> +  if (Enable) {
>> +    Val |= WDT_CTRL_WCS_ENABLE_MASK;
>> +  } else {
>> +    Val &= ~WDT_CTRL_WCS_ENABLE_MASK;
>> +  }
>> +  MmioWrite32 ((UINTN)(WDT_CTRL_BASE_REG + WDT_CTRL_WCS_OFF), Val);
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +WatchdogTimerSetup (
>> +  VOID
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +
>> +  /* Disable Watchdog timer */
>> +  WatchdogTimerEnable (FALSE);
>> +
>> +  if (!mInterruptWS0Enabled) {
>> +    Status = mInterruptProtocol->EnableInterruptSource (
>> +                                   mInterruptProtocol,
>> +                                   WS0_INTERRUPT_SOURCE
>> +                                   );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    mInterruptWS0Enabled = TRUE;
>> +  }
>> +
>> +  if (mNumTimerTicks == 0) {
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  /* If the number of required ticks is greater than the max the Watchdog's
>> +     offset register (WOR) can hold, we need to manually compute and set
>> +     the compare register (WCV) */
>> +  if (mNumTimerTicks > MAX_UINT32) {
>> +    /* We need to enable the Watchdog *before* writing to the compare register,
>> +       because enabling the Watchdog causes an "explicit refresh", which
>> +       clobbers the compare register (WCV). In order to make sure this doesn't
>> +       trigger an interrupt, set the offset to max. */
>> +    WatchdogTimerWriteOffsetRegister (MAX_UINT32);
>> +    WatchdogTimerEnable (TRUE);
>> +    WatchdogTimerWriteCompareRegister (ArmGenericTimerGetSystemCount () + mNumTimerTicks);
>> +  } else {
>> +    WatchdogTimerWriteOffsetRegister ((UINT32)mNumTimerTicks);
>> +    WatchdogTimerEnable (TRUE);
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +
>> +/* This function is called when the Watchdog's first signal (WS0) goes high.
>> +   It uses the ResetSystem Runtime Service to reset the board.
>> +*/
>> +VOID
>> +EFIAPI
>> +WatchdogTimerInterruptHandler (
>> +  IN HARDWARE_INTERRUPT_SOURCE Source,
>> +  IN EFI_SYSTEM_CONTEXT        SystemContext
>> +  )
>> +{
>> +  STATIC CONST CHAR16 ResetString[]= L"The generic Watchdog timer ran out.";
>> +
>> +  mInterruptProtocol->EndOfInterrupt (mInterruptProtocol, Source);
>> +
>> +  if (!IsFailSafeOff ()) {
>> +    /* Not handling interrupt as ATF is monitoring it */
>> +    return;
>> +  }
>> +
>> +  WatchdogTimerEnable (FALSE);
>> +
>> +  gRT->ResetSystem (
>> +         EfiResetCold,
>> +         EFI_TIMEOUT,
>> +         StrSize (ResetString),
>> +         (VOID *)&ResetString
>> +         );
>> +
>> +  /* If we got here then the reset didn't work */
>> +  ASSERT (FALSE);
>> +}
>> +
>> +/**
>> +  This function registers the handler NotifyFunction so it is called every time
>> +  the Watchdog timer expires.  It also passes the amount of time since the last
>> +  handler call to the NotifyFunction.
>> +  If NotifyFunction is not NULL and a handler is not already registered,
>> +  then the new handler is registered and EFI_SUCCESS is returned.
>> +  If NotifyFunction is NULL, and a handler is already registered,
>> +  then that handler is unregistered.
>> +  If an attempt is made to register a handler when a handler is already
>> +  registered, then EFI_ALREADY_STARTED is returned.
>> +  If an attempt is made to unregister a handler when a handler is not
>> +  registered, then EFI_INVALID_PARAMETER is returned.
>> +
>> +  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
>> +  @param  NotifyFunction   The function to call when a timer interrupt fires.
>> +                           This function executes at TPL_HIGH_LEVEL. The DXE
>> +                           Core will register a handler for the timer interrupt,
>> +                           so it can know how much time has passed. This
>> +                           information is used to signal timer based events.
>> +                           NULL will unregister the handler.
>> +
>> +  @retval EFI_UNSUPPORTED       The code does not support NotifyFunction.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +WatchdogTimerRegisterHandler (
>> +  IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
>> +  IN       EFI_WATCHDOG_TIMER_NOTIFY        NotifyFunction
>> +  )
>> +{
>> +  /* Not support. Watchdog will reset the board */
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +/**
>> +  This function sets the amount of time to wait before firing the Watchdog
>> +  timer to TimerPeriod 100ns units.  If TimerPeriod is 0, then the Watchdog
>> +  timer is disabled.
>> +
>> +  @param  This             The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
>> +  @param  TimerPeriod      The amount of time in 100ns units to wait before
>> +                           the Watchdog timer is fired. If TimerPeriod is zero,
>> +                           then the Watchdog timer is disabled.
>> +
>> +  @retval EFI_SUCCESS           The Watchdog timer has been programmed to fire
>> +                                in Time  100ns units.
>> +  @retval EFI_DEVICE_ERROR      A Watchdog timer could not be programmed due
>> +                                to a device error.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +WatchdogTimerSetPeriod (
>> +  IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
>> +  IN       UINT64                           TimerPeriod   // In 100ns units
>> +  )
>> +{
>> +  mNumTimerTicks  = (ArmGenericTimerGetTimerFreq () * TimerPeriod) / TIME_UNITS_PER_SECOND;
>> +
>> +  if (!IsFailSafeOff ()) {
>> +    /* Not support Watchdog timer service until FailSafe is off as ATF is monitoring it */
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  return WatchdogTimerSetup ();
>> +}
>> +
>> +/**
>> +  This function retrieves the period of timer interrupts in 100ns units,
>> +  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
>> +  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
>> +  returned, then the timer is currently disabled.
>> +
>> +  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
>> +  @param  TimerPeriod      A pointer to the timer period to retrieve in
>> +                           100ns units. If 0 is returned, then the timer is
>> +                           currently disabled.
>> +
>> +
>> +  @retval EFI_SUCCESS           The timer period was returned in TimerPeriod.
>> +  @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +WatchdogTimerGetPeriod (
>> +  IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
>> +  OUT      UINT64                           *TimerPeriod
>> +  )
>> +{
>> +  if (TimerPeriod == NULL) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  *TimerPeriod = ((TIME_UNITS_PER_SECOND / ArmGenericTimerGetTimerFreq ()) * mNumTimerTicks);
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Interface structure for the Watchdog Architectural Protocol.
>> +
>> +  @par Protocol Description:
>> +  This protocol provides a service to set the amount of time to wait
>> +  before firing the Watchdog timer, and it also provides a service to
>> +  register a handler that is invoked when the Watchdog timer fires.
>> +
>> +  @par When the Watchdog timer fires, control will be passed to a handler
>> +  if one has been registered.  If no handler has been registered,
>> +  or the registered handler returns, then the system will be
>> +  reset by calling the Runtime Service ResetSystem().
>> +
>> +  @param RegisterHandler
>> +  Registers a handler that will be called each time the
>> +  Watchdogtimer interrupt fires.  TimerPeriod defines the minimum
>> +  time between timer interrupts, so TimerPeriod will also
>> +  be the minimum time between calls to the registered
>> +  handler.
>> +  NOTE: If the Watchdog resets the system in hardware, then
>> +        this function will not have any chance of executing.
>> +
>> +  @param SetTimerPeriod
>> +  Sets the period of the timer interrupt in 100ns units.
>> +  This function is optional, and may return EFI_UNSUPPORTED.
>> +  If this function is supported, then the timer period will
>> +  be rounded up to the nearest supported timer period.
>> +
>> +  @param GetTimerPeriod
>> +  Retrieves the period of the timer interrupt in 100ns units.
>> +
>> +**/
>> +STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = {
>> +  (EFI_WATCHDOG_TIMER_REGISTER_HANDLER)WatchdogTimerRegisterHandler,
>> +  (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD)WatchdogTimerSetPeriod,
>> +  (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD)WatchdogTimerGetPeriod
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +WatchdogTimerInstallProtocol (
>> +  EFI_WATCHDOG_TIMER_ARCH_PROTOCOL **WatchdogTimerProtocol
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +  EFI_HANDLE Handle;
>> +  EFI_TPL    CurrentTpl;
>> +
>> +  /* Make sure the Watchdog Timer Architectural Protocol has not been installed
>> +     in the system yet.
>> +     This will avoid conflicts with the universal Watchdog */
>> +  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtocolGuid);
>> +
>> +  ASSERT (ArmGenericTimerGetTimerFreq () != 0);
>> +
>> +  /* Install interrupt handler */
>> +  Status = gBS->LocateProtocol (
>> +                  &gHardwareInterrupt2ProtocolGuid,
>> +                  NULL,
>> +                  (VOID **)&mInterruptProtocol
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  /*
>> +   * We don't want to be interrupted while registering Watchdog interrupt source as the interrupt
>> +   * may be trigger in the middle because the interrupt line already enabled in the EL3.
>> +   */
>> +  CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
>> +
>> +  Status = mInterruptProtocol->RegisterInterruptSource (
>> +                                 mInterruptProtocol,
>> +                                 WS0_INTERRUPT_SOURCE,
>> +                                 WatchdogTimerInterruptHandler
>> +                                 );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  /* Don't enable interrupt until FailSafe off */
>> +  mInterruptWS0Enabled = FALSE;
>> +  Status = mInterruptProtocol->DisableInterruptSource (
>> +                                 mInterruptProtocol,
>> +                                 WS0_INTERRUPT_SOURCE
>> +                                 );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  gBS->RestoreTPL (CurrentTpl);
>> +
>> +  Status = mInterruptProtocol->SetTriggerType (
>> +                                 mInterruptProtocol,
>> +                                 WS0_INTERRUPT_SOURCE,
>> +                                 EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
>> +                                 );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  /* Install the Timer Architectural Protocol onto a new handle */
>> +  Handle = NULL;
>> +  Status = gBS->InstallMultipleProtocolInterfaces (
>> +                  &Handle,
>> +                  &gEfiWatchdogTimerArchProtocolGuid,
>> +                  &gWatchdogTimer,
>> +                  NULL
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  mNumTimerTicks = 0;
>> +
>> +  if (WatchdogTimerProtocol != NULL) {
>> +    *WatchdogTimerProtocol = &gWatchdogTimer;
>> +  }
>> +
>> +  return Status;
>> +}
>> -- 
>> 2.17.1
>>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76542): https://edk2.groups.io/g/devel/message/76542
Mute This Topic: https://groups.io/mt/83097098/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list