From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) by mx.groups.io with SMTP id smtpd.web11.6203.1622848083197215097 for ; Fri, 04 Jun 2021 16:08:03 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=pS4QWxz/; spf=pass (domain: nuviainc.com, ip: 209.85.221.41, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f41.google.com with SMTP id h8so10740207wrz.8 for ; Fri, 04 Jun 2021 16:08:02 -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=qBHRoiZIAi1i7qvM3OhCwaF1Pp3Z0W+HL8JH8dh3VEs=; b=pS4QWxz/VLcdee0ay/OFRbTBrbeit+iaHk0ULAGablkP/WpWCQIjxRhACi7kxjSy3s lC3ujhKCsJAuTBzfxW15wZjHsRJcO3yU6iALwAV+8NXqWiNDpfwMSxv944NUcnnu1lGA rckvha1E+yEjMRRwGp+ArcLgA0FRCLUCWdl+ijy66pPALgbVXVWYtBX+5BTRytgAopxZ VwddKKAEPr3isaV+zy2XpqlqPKcQHjC5gjrLiyptdwwE0c7j+Eprrb7/yDAMo6DcOmJ2 o7TouhULlpIlu0zcKKIN+uV1u00YX1jh5MzXO8a5qKPvy9ob7fCR9JHeVSr11UTlMUAl o6aw== 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=qBHRoiZIAi1i7qvM3OhCwaF1Pp3Z0W+HL8JH8dh3VEs=; b=S/52yxpfZD/DDfdtxVzGa98EsqN4Lqy/SxsrhmpuZbkgZLjNvOe//xr2F1lHA065lR JwGhFwBf7mRS6DIFhm+zWdSIhoAmKgj657NYU3tptswfyp9Go3rapughIo1fZa9+UymT 0Xih/H0Wrh2IVmbjilOqAi31xOyhXMvpzta86Tz+yXjVvI9rRnTkiI7VSPpJ1T+ugh/i BEg9mNZHtlfYHSeN84Vql3SowDWnze0mIKucALvNk2UcJdAFsKbrYzvlPxJedZfdh2q6 Z67LXh9yr58+UzlqO8XEEYu6vOxIkJt4Pp+WqGl2sQqAPLxSLDwMbP+AS4uDlMUkmC4M H+CA== X-Gm-Message-State: AOAM532R6lwxuRP2BNsPclFEqhMvFuItQobughZi3DKn2qrOmfUHN9Se y3VEu+h+iFws+0RuMnVAasj9/A== X-Google-Smtp-Source: ABdhPJzr+WmIZk//LIELjEkQ0cJITTJD/FO7kvgk8Y3nO37j7lwYcOcoWCYJTBFzuFC3OMy0owJn1w== X-Received: by 2002:a5d:440a:: with SMTP id z10mr5868311wrq.323.1622848081600; Fri, 04 Jun 2021 16:08:01 -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 v10sm8564378wre.33.2021.06.04.16.08.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Jun 2021 16:08:01 -0700 (PDT) Date: Sat, 5 Jun 2021 00:07:59 +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 03/32] AmperePlatformPkg: Implement FailSafe library Message-ID: <20210604230759.gzjursd3sg3jijn7@leviathan> References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-5-nhi@os.amperecomputing.com> MIME-Version: 1.0 In-Reply-To: <20210526100724.5359-5-nhi@os.amperecomputing.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, May 26, 2021 at 17:06:55 +0700, Nhi Pham wrote: > The Ampere Altra System Firmware provides a fail-safe feature to help > recover the system if there are setting changes such as Core voltage, > DRAM parameters that cause the UEFI failed to boot. > > The FailSafeLib supports API calls to Secure World to: > * Get the FailSafe region information. > * Get the current FailSafe status. > * Inform to FailSafe monitor that the system boots successfully. > * Simulate UEFI boot failure due to config wrong NVPARAM for > testing failsafe feature. > > This library will be consumed by FailSafe DXE driver. > > 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 Reviewed-by: Leif Lindholm > --- > Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec | 3 + > Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.inf | 41 +++ > Platform/Ampere/AmperePlatformPkg/Include/Library/FailSafeLib.h | 62 ++++ > Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.c | 320 ++++++++++++++++++++ > 4 files changed, 426 insertions(+) > > diff --git a/Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec b/Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec > index 7c1d1f84f780..6e33d96c7ea5 100755 > --- a/Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec > +++ b/Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec > @@ -22,7 +22,10 @@ [Defines] > # > ################################################################################ > [Includes] > + Include # Root include for the package > > [LibraryClasses] > + ## @libraryclass Provides functions to support FailSafe operations. > + FailSafeLib|Platform/Ampere/AmperePlatformPkg/Include/Library/FailSafeLib.h > > [Guids] > diff --git a/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.inf b/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.inf > new file mode 100755 > index 000000000000..456b9d5fc85b > --- /dev/null > +++ b/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.inf > @@ -0,0 +1,41 @@ > +## @file > +# > +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001B > + BASE_NAME = FailSafeLib > + FILE_GUID = 3403D080-6D76-11E7-907B-A6006AD3DBA0 > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = FailSafeLib > + > +[Sources] > + FailSafeLib.c > + > +[Protocols] > + gEfiMmCommunicationProtocolGuid ## CONSUMES > + > +[Packages] > + ArmPkg/ArmPkg.dec > + ArmPlatformPkg/ArmPlatformPkg.dec > + MdePkg/MdePkg.dec > + Platform/Ampere/AmperePlatformPkg/AmperePlatformPkg.dec > + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec > + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec > + > +[LibraryClasses] > + ArmSmcLib > + BaseLib > + BaseMemoryLib > + DebugLib > + HobLib > + IoLib > + NVParamLib > + > +[Guids] > + gSpiNorMmGuid > diff --git a/Platform/Ampere/AmperePlatformPkg/Include/Library/FailSafeLib.h b/Platform/Ampere/AmperePlatformPkg/Include/Library/FailSafeLib.h > new file mode 100644 > index 000000000000..7ebd1c8a74a2 > --- /dev/null > +++ b/Platform/Ampere/AmperePlatformPkg/Include/Library/FailSafeLib.h > @@ -0,0 +1,62 @@ > +/** @file > + > + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef FAILSAFE_LIB_H_ > +#define FAILSAFE_LIB_H_ > + > +enum { > + MM_SPINOR_FUNC_GET_INFO, > + MM_SPINOR_FUNC_READ, > + MM_SPINOR_FUNC_WRITE, > + MM_SPINOR_FUNC_ERASE, > + MM_SPINOR_FUNC_GET_NVRAM_INFO, > + MM_SPINOR_FUNC_GET_NVRAM2_INFO, > + MM_SPINOR_FUNC_GET_FAILSAFE_INFO > +}; > + > +#define MM_SPINOR_RES_SUCCESS 0xAABBCC00 > +#define MM_SPINOR_RES_FAIL 0xAABBCCFF > + > +enum { > + FAILSAFE_BOOT_NORMAL = 0, > + FAILSAFE_BOOT_LAST_KNOWN_SETTINGS, > + FAILSAFE_BOOT_DEFAULT_SETTINGS, > + FAILSAFE_BOOT_DDR_DOWNGRADE, > + FAILSAFE_BOOT_SUCCESSFUL > +}; > + > +/** > + Get the FailSafe region information. > +**/ > +EFI_STATUS > +EFIAPI > +FailSafeGetRegionInfo ( > + UINT64 *Offset, > + UINT64 *Size > + ); > + > +/** > + Inform to FailSafe monitor that the system boots successfully. > +**/ > +EFI_STATUS > +EFIAPI > +FailSafeBootSuccessfully ( > + VOID > + ); > + > +/** > + Simulate UEFI boot failure due to config wrong NVPARAM for > + testing failsafe feature > +**/ > +EFI_STATUS > +EFIAPI > +FailSafeTestBootFailure ( > + VOID > + ); > + > +#endif /* FAILSAFE_LIB_H_ */ > diff --git a/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.c b/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.c > new file mode 100644 > index 000000000000..a567ab91375f > --- /dev/null > +++ b/Platform/Ampere/AmperePlatformPkg/Library/FailSafeLib/FailSafeLib.c > @@ -0,0 +1,320 @@ > +/** @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 > +#include > +#include > + > +#define EFI_MM_MAX_PAYLOAD_U64_E 10 > +#define EFI_MM_MAX_PAYLOAD_SIZE (EFI_MM_MAX_PAYLOAD_U64_E * sizeof (UINT64)) > + > +EFI_MM_COMMUNICATION_PROTOCOL *mFlashLibMmCommProtocol = NULL; > + > +typedef struct { > + /* Allows for disambiguation of the message format */ > + EFI_GUID HeaderGuid; > + /* > + * Describes the size of Data (in bytes) and does not include the size > + * of the header > + */ > + UINTN MsgLength; > +} EFI_MM_COMM_HEADER_NOPAYLOAD; > + > +typedef struct { > + UINT64 Data[EFI_MM_MAX_PAYLOAD_U64_E]; > +} EFI_MM_COMM_SPINOR_PAYLOAD; > + > +typedef struct { > + EFI_MM_COMM_HEADER_NOPAYLOAD EfiMmHdr; > + EFI_MM_COMM_SPINOR_PAYLOAD PayLoad; > +} EFI_MM_COMM_REQUEST; > + > +typedef struct { > + UINT64 Status; > +} EFI_MM_COMMUNICATE_SPINOR_RES; > + > +typedef struct { > + UINT64 Status; > + UINT64 FailSafeBase; > + UINT64 FailSafeSize; > +} EFI_MM_COMMUNICATE_SPINOR_FAILSAFE_INFO_RES; > + > +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq; > + > +#pragma pack(1) > +typedef struct { > + UINT8 ImgMajorVer; > + UINT8 ImgMinorVer; > + UINT32 NumRetry1; > + UINT32 NumRetry2; > + UINT32 MaxRetry; > + UINT8 Status; > + /* > + * Byte[3]: Reserved > + * Byte[2]: Slave MCU Failure Mask > + * Byte[1]: Reserved > + * Byte[0]: Master MCU Failure Mask > + */ > + UINT32 MCUFailsMask; > + UINT16 CRC16; > + UINT8 Reserved[3]; > +} FAIL_SAFE_CONTEXT; > + > +#pragma pack() > + > +STATIC > +EFI_STATUS > +UefiMmCreateSpiNorReq ( > + VOID *Data, > + UINT64 Size > + ) > +{ > + CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid); > + mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size; > + > + if (Size != 0) { > + ASSERT (Data); > + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE); > + > + CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size); > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +INTN > +CheckCrc16 ( > + UINT8 *Pointer, > + INTN Count > + ) > +{ > + INTN Crc = 0; > + INTN Index; > + > + while (--Count >= 0) { > + Crc = Crc ^ (INTN)*Pointer++ << 8; > + for (Index = 0; Index < 8; ++Index) { > + if ((Crc & 0x8000) != 0) { > + Crc = Crc << 1 ^ 0x1021; > + } else { > + Crc = Crc << 1; > + } > + } > + } > + > + return Crc & 0xFFFF; > +} > + > +BOOLEAN > +FailSafeValidCRC ( > + FAIL_SAFE_CONTEXT *FailSafeBuf > + ) > +{ > + UINT8 Valid; > + UINT16 Crc; > + UINT32 Len; > + > + Len = sizeof (FAIL_SAFE_CONTEXT); > + Crc = FailSafeBuf->CRC16; > + FailSafeBuf->CRC16 = 0; > + > + Valid = (Crc == CheckCrc16 ((UINT8 *)FailSafeBuf, Len)); > + FailSafeBuf->CRC16 = Crc; > + > + return Valid; > +} > + > +BOOLEAN > +FailSafeFailureStatus ( > + UINT8 Status > + ) > +{ > + if ((Status == FAILSAFE_BOOT_LAST_KNOWN_SETTINGS) || > + (Status == FAILSAFE_BOOT_DEFAULT_SETTINGS) || > + (Status == FAILSAFE_BOOT_DDR_DOWNGRADE)) > + { > + return TRUE; > + } > + > + return FALSE; > +} > + > +EFI_STATUS > +EFIAPI > +FailSafeGetRegionInfo ( > + UINT64 *Offset, > + UINT64 *Size > + ) > +{ > + EFI_MM_COMMUNICATE_SPINOR_FAILSAFE_INFO_RES *MmSpiNorFailSafeInfoRes; > + UINT64 MmData[5]; > + UINTN DataSize; > + EFI_STATUS Status; > + > + if (mFlashLibMmCommProtocol == NULL) { > + Status = gBS->LocateProtocol ( > + &gEfiMmCommunicationProtocolGuid, > + NULL, > + (VOID **)&mFlashLibMmCommProtocol > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: Can't locate gEfiMmCommunicationProtocolGuid\n", __FUNCTION__)); > + return Status; > + } > + } > + > + MmData[0] = MM_SPINOR_FUNC_GET_FAILSAFE_INFO; > + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData)); > + > + DataSize = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); > + Status = mFlashLibMmCommProtocol->Communicate ( > + mFlashLibMmCommProtocol, > + (VOID *)&mEfiMmSpiNorReq, > + &DataSize > + ); > + ASSERT_EFI_ERROR (Status); > + > + MmSpiNorFailSafeInfoRes = (EFI_MM_COMMUNICATE_SPINOR_FAILSAFE_INFO_RES *)&mEfiMmSpiNorReq.PayLoad; > + if (MmSpiNorFailSafeInfoRes->Status != MM_SPINOR_RES_SUCCESS) { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Get flash information failed: 0x%llx\n", > + __FUNCTION__, > + MmSpiNorFailSafeInfoRes->Status > + )); > + return EFI_DEVICE_ERROR; > + } > + > + *Offset = MmSpiNorFailSafeInfoRes->FailSafeBase; > + *Size = MmSpiNorFailSafeInfoRes->FailSafeSize; > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +EFIAPI > +FailSafeBootSuccessfully ( > + VOID > + ) > +{ > + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes; > + UINT64 MmData[5]; > + UINTN Size; > + EFI_STATUS Status; > + UINT64 FailSafeStartOffset; > + UINT64 FailSafeSize; > + FAIL_SAFE_CONTEXT FailSafeBuf; > + > + Status = FailSafeGetRegionInfo (&FailSafeStartOffset, &FailSafeSize); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: Failed to get context region information\n", __FUNCTION__)); > + return EFI_DEVICE_ERROR; > + } > + > + MmData[0] = MM_SPINOR_FUNC_READ; > + MmData[1] = FailSafeStartOffset; > + MmData[2] = (UINT64)sizeof (FAIL_SAFE_CONTEXT); > + MmData[3] = (UINT64)&FailSafeBuf; > + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData)); > + > + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); > + Status = mFlashLibMmCommProtocol->Communicate ( > + mFlashLibMmCommProtocol, > + (VOID *)&mEfiMmSpiNorReq, > + &Size > + ); > + ASSERT_EFI_ERROR (Status); > + > + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; > + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Read context failed: 0x%llx\n", > + __FUNCTION__, > + MmSpiNorRes->Status > + )); > + return EFI_DEVICE_ERROR; > + } > + > + /* > + * If failsafe context is invalid, it is already indicate a successful boot > + * and don't need to be cleared > + */ > + if (!FailSafeValidCRC (&FailSafeBuf)) { > + return EFI_SUCCESS; > + } > + > + /* > + * If failsafe context is valid, and: > + * - The status indicate non-failure, then don't clear it > + * - The status indicate a failure, then go and clear it > + */ > + if (!FailSafeFailureStatus (FailSafeBuf.Status)) { > + return EFI_SUCCESS; > + } > + > + MmData[0] = MM_SPINOR_FUNC_ERASE; > + MmData[1] = FailSafeStartOffset; > + MmData[2] = FailSafeSize; > + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData)); > + > + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); > + Status = mFlashLibMmCommProtocol->Communicate ( > + mFlashLibMmCommProtocol, > + (VOID *)&mEfiMmSpiNorReq, > + &Size > + ); > + ASSERT_EFI_ERROR (Status); > + > + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; > + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Erase context failed: 0x%llx\n", > + __FUNCTION__, > + MmSpiNorRes->Status > + )); > + return EFI_DEVICE_ERROR; > + } > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +EFIAPI > +FailSafeTestBootFailure ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINT32 Value = 0; > + > + /* > + * Simulate UEFI boot failure due to config wrong NVPARAM for > + * testing failsafe feature > + */ > + Status = NVParamGet (NV_UEFI_FAILURE_FAILSAFE_OFFSET, NV_PERM_ALL, &Value); > + if (!EFI_ERROR (Status) && (Value == 1)) { > + while (1) { > + } > + } > + > + return EFI_SUCCESS; > +} > -- > 2.17.1 >