From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) by mx.groups.io with SMTP id smtpd.web09.6349.1622848375190247587 for ; Fri, 04 Jun 2021 16:12:55 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=oKh2sNPE; spf=pass (domain: nuviainc.com, ip: 209.85.221.50, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f50.google.com with SMTP id l2so10789426wrw.6 for ; Fri, 04 Jun 2021 16:12:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=vPzR59yoW4i8ME+BQY+/UFOt2l1wlFPPZGbSgriF+Lo=; b=oKh2sNPEhucwCH8sE9OA8fK6P1FbARIK3QzaUlQDp2jYxwdR06uTOn6AL32mxW3dKE f/hLw6BueeCCmsvLG7hV+Wo39GpBiKnB9ypGr2kTP4XeouZ4wrawcKqbIxrCnP7UCSOg Nr1CHTOJtNafqZepDHESVm1zg1AaOEpCyDH5h0ynYsY152ZPCGBkg6m3qXZY0ncii6Rg dxV+nzfUi2KqQhgTuVb7OkaBeNIyV4bXv+93ZiKQLOQOBzUKmgzd+2VkLuqO31BTnnMN 5fg1dfgG0yoI8p2kcsELM/zTrUQCmbJBR+Rx05dhrespYDxPqsQRhPPENbl4SUWNnO/O PzHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=vPzR59yoW4i8ME+BQY+/UFOt2l1wlFPPZGbSgriF+Lo=; b=OQ1cSZ7Z6N8ekuBD3oT+k+xFXRllvuHDl493kQKwnbqFpAsAIguLBe5823HzNgsnCh zXQXGEh1vmMXFVdw7lZ9InomYgXofNsrzncIGe14Rom9+b1LzYghnQ+k+oGHIrcAzyKD fh9uh9iVG2Dm1pFCFc9oCcFImdsHHZhdvIuDIs2QvJ788xwaiuO6M4ahCNcgEKzxg7N6 vq2p+xO5us9nh+5HboLOl89Zvsoq58tbNtikocqc8RynJJikf44n1uUJg8CCEQSjnsc/ RaoK+/ZB9o9L95iLm2Bt9EKRYMxR6McK7bHIaPFEqmUrA90YAY3BXFg8et7hSpYskKHM NaYw== X-Gm-Message-State: AOAM532fC6Xtx/GQ13MxXezf93olfnjLTjG4/ol68iIwukZOnVZnoq48 hM7z0qcWCVKcb+8DyfVHZUqbhQ== X-Google-Smtp-Source: ABdhPJweupo4vYnnHxLN6fKkxu41IUmuLCl1IYtGvWFHDU785RnMXLbBse85kUAlbBlHp+LlCs99rg== X-Received: by 2002:adf:de03:: with SMTP id b3mr6100482wrm.15.1622848373673; Fri, 04 Jun 2021 16:12:53 -0700 (PDT) Return-Path: Received: from leviathan (cpc1-cmbg19-2-0-cust915.5-4.cable.virginm.net. [82.27.183.148]) by smtp.gmail.com with ESMTPSA id o9sm7478729wrw.69.2021.06.04.16.12.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Jun 2021 16:12:53 -0700 (PDT) Date: Sat, 5 Jun 2021 00:12:51 +0100 From: "Leif Lindholm" To: Nhi Pham Cc: devel@edk2.groups.io, Thang Nguyen , Chuong Tran , Phong Vo , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: Re: [edk2-platforms][PATCH v2 04/32] AmperePlatformPkg: Add FailSafe and WDT support Message-ID: <20210604231251.qdmtx7tzf2ph4d2p@leviathan> References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-6-nhi@os.amperecomputing.com> MIME-Version: 1.0 In-Reply-To: <20210526100724.5359-6-nhi@os.amperecomputing.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 > Cc: Chuong Tran > Cc: Phong Vo > Cc: Leif Lindholm > Cc: Michael D Kinney > Cc: Ard Biesheuvel > Cc: Nate DeSimone > > Signed-off-by: Nhi Pham > --- > 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. / 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.
> +# > +# 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef FAILSAFE_H_ > +#define FAILSAFE_H_ > + > +#include > + > +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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef GENERIC_WATCHDOG_H_ > +#define GENERIC_WATCHDOG_H_ > + > +#include > + > +/* 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 >