public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nhi Pham" <nhi@os.amperecomputing.com>
To: devel@edk2.groups.io
Cc: Nhi Pham <nhi@os.amperecomputing.com>
Subject: [edk2-platforms][PATCH 25/34] AmpereAltraPkg: Implement PlatformFlashAccessLib instance
Date: Wed,  9 Dec 2020 16:25:22 +0700	[thread overview]
Message-ID: <20201209092531.30867-26-nhi@os.amperecomputing.com> (raw)
In-Reply-To: <20201209092531.30867-1-nhi@os.amperecomputing.com>

This library provides API functions to perform flash write operation
via Secure UEFI MM interface.

The platform flash device is controlled by Arm Trusted Firmware (ATF)
in the secure world. UEFI can not write directly an update image
to the flash device. So, this instance of PlatformFlashAccessLib is
implemented to transfer the update image to ATF secure world via the
Firmware Update SMC service. Then that service will proceed the update.

Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf |  37 +++
 Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c   | 318 ++++++++++++++++++++
 2 files changed, 355 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
new file mode 100644
index 000000000000..fddc0dfbb916
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
@@ -0,0 +1,37 @@
+## @file
+#  Platform flash device access library.
+#
+#  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = PlatformFlashAccessLib
+  FILE_GUID                      = C2821AC7-331A-48FC-90C2-6660ED40EB25
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformFlashAccessLib|DXE_DRIVER
+
+[Sources]
+  PlatformFlashAccessLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  SignedCapsulePkg/SignedCapsulePkg.dec
+  ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gEfiMmCommunicationProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
new file mode 100644
index 000000000000..ecb08431ac01
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
@@ -0,0 +1,318 @@
+/** @file
+  Platform flash device access library.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/PlatformFlashAccessLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/MmCommunication.h>
+
+EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunication = NULL;
+
+#define EFI_MM_MAX_PAYLOAD_U64_E 10
+#define EFI_MM_MAX_PAYLOAD_SIZE  (EFI_MM_MAX_PAYLOAD_U64_E * sizeof (UINT64))
+
+/* FWU MM GUID */
+STATIC CONST EFI_GUID mFwuMmGuid = { 0x452240CD, 0xB3B3, 0x4695, { 0x9A, 0x63, 0xDF, 0xEC, 0x50, 0x82, 0xE7, 0x7A } };
+
+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_FWU_PAYLOAD;
+
+typedef struct {
+  EFI_MM_COMM_HEADER_NOPAYLOAD  EfiMmHdr;
+  EFI_MM_COMM_FWU_PAYLOAD       PayLoad;
+} EFI_MM_COMM_REQUEST;
+
+EFI_MM_COMM_REQUEST mEfiMmSysFwuReq;
+
+typedef struct {
+  UINT64 Status;
+  UINT64 Progress;
+} EFI_MM_COMMUNICATE_FWU_RES;
+
+#define FWU_MM_RES_SUCCESS              0xAABBCC00
+#define FWU_MM_RES_IN_PROGRESS          0xAABBCC01
+#define FWU_MM_RES_SECURITY_VIOLATION   0xAABBCC02
+#define FWU_MM_RES_OUT_OF_RESOURCES     0xAABBCC03
+#define FWU_MM_RES_IO_ERROR             0xAABBCC04
+#define FWU_MM_RES_FAIL                 0xAABBCCFF
+
+/*
+ * The ARM Trusted Firmware (ATF) defined image types to support updating
+ * various firmware via SMC Firmware Update service.
+ * The value of definition here must be the same in ATF code.
+ */
+#define FWU_IMG_TYPE_INVALID   0
+#define FWU_IMG_TYPE_ATFBIOS   2 // ARM Trusted Firmware and UEFI Image
+#define FWU_IMG_TYPE_MAX       5
+
+/*
+ * According to PLATFORM_FIRMWARE_TYPE,
+ * Type 0x80000000 ~ 0xFFFFFFFF is reserved for OEM.
+ * A type of firmware image is determined by FirmwareType value
+ * in the Configuration of Firmware Update.
+ * Formula: FirmwareType = ImageType + 0x80000000
+ */
+#define FIRMWARE_TYPE_OEM_OFFSET 0x80000000
+
+/*
+ * Size of Firmware Descriptor File Volume
+ */
+#define FIRMWARE_DESCRIPTOR_SIZE 0x10000
+
+VOID
+UefiMmCreateSysFwuReq (
+  VOID    *Data,
+  UINT64  Size
+  )
+{
+  CopyGuid (&mEfiMmSysFwuReq.EfiMmHdr.HeaderGuid, &mFwuMmGuid);
+  mEfiMmSysFwuReq.EfiMmHdr.MsgLength = Size;
+
+  if (Size != 0) {
+    ASSERT (Data != NULL);
+    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
+
+    CopyMem (&mEfiMmSysFwuReq.PayLoad.Data, Data, Size);
+  }
+}
+
+EFI_STATUS
+MmFlashUpdate (
+  IN UINT32                                         ImageType,
+  IN VOID                                           *FirmwareImage,
+  IN UINT64                                         ImageSize,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  )
+{
+  EFI_MM_COMMUNICATE_FWU_RES  *MmFwuStatus;
+  UINTN                       ProgressUpdate = StartPercentage;
+  UINTN                       Size;
+  UINT64                      MmData[5];
+  EFI_STATUS                  Status;
+
+  if (FirmwareImage == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a:%d Invalid inputs.\n", __FUNCTION__, __LINE__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a:%d Image: %p Size 0x%lx\n",
+          __FUNCTION__, __LINE__, FirmwareImage, ImageSize));
+
+  if (mMmCommunication == NULL) {
+    Status = gBS->LocateProtocol(
+                    &gEfiMmCommunicationProtocolGuid,
+                    NULL,
+                    (VOID **) &mMmCommunication);
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Can't locate gEfiMmCommunicationProtocolGuid.\n", __FUNCTION__));
+      return Status;
+    }
+  }
+
+  MmData[0] = ImageType;
+  MmData[1] = ImageSize;
+  MmData[2] = (UINT64) FirmwareImage;
+  MmData[3] = 1; // MM yield for progress reporting.
+
+  while (TRUE) {
+    UefiMmCreateSysFwuReq ((VOID *) &MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = mMmCommunication->Communicate (
+                                 mMmCommunication,
+                                 (VOID *) &mEfiMmSysFwuReq,
+                                 &Size
+                                 );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a:%d MM communication error - %r\n",
+              __FUNCTION__, __LINE__, Status));
+      return EFI_DEVICE_ERROR;
+    }
+
+    /* Return data in the first double word of payload */
+    MmFwuStatus = (EFI_MM_COMMUNICATE_FWU_RES *) mEfiMmSysFwuReq.PayLoad.Data;
+    if (MmFwuStatus->Status == FWU_MM_RES_IN_PROGRESS) {
+      if (NULL != Progress) {
+        Progress (ProgressUpdate);
+      }
+
+      ProgressUpdate = StartPercentage +
+          (((EndPercentage - StartPercentage) * (MmFwuStatus->Progress)) / 100);
+      continue;
+    }
+    break;
+  }
+
+  switch (MmFwuStatus->Status) {
+  case FWU_MM_RES_SUCCESS:
+    if (NULL != Progress) {
+      Progress (EndPercentage);
+    }
+    Status = EFI_SUCCESS;
+    break;
+
+  case FWU_MM_RES_SECURITY_VIOLATION:
+    DEBUG ((DEBUG_ERROR, "%a:%d Failed to update - Security Violation!\n",
+            __FUNCTION__, __LINE__));
+    Status = EFI_SECURITY_VIOLATION;
+    break;
+
+  case FWU_MM_RES_OUT_OF_RESOURCES:
+    DEBUG ((DEBUG_ERROR, "%a:%d Failed to update - Insufficient resources!\n",
+            __FUNCTION__, __LINE__));
+    Status = EFI_OUT_OF_RESOURCES;
+    break;
+
+  case FWU_MM_RES_IO_ERROR:
+    DEBUG ((DEBUG_ERROR, "%a:%d Failed to update - IO Error!\n",
+            __FUNCTION__, __LINE__));
+    Status = EFI_DEVICE_ERROR;
+    break;
+
+  default:
+    DEBUG ((DEBUG_ERROR, "%a:%d Failed to update - Unknown Error!\n",
+            __FUNCTION__, __LINE__));
+    Status = EFI_INVALID_PARAMETER;
+    break;
+  }
+
+  return Status;
+}
+
+/**
+  Perform flash write operation with progress indicator.  The start and end
+  completion percentage values are passed into this function.  If the requested
+  flash write operation is broken up, then completion percentage between the
+  start and end values may be passed to the provided Progress function.  The
+  caller of this function is required to call the Progress function for the
+  start and end completion percentage values.  This allows the Progress,
+  StartPercentage, and EndPercentage parameters to be ignored if the requested
+  flash write operation can not be broken up
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+  @param[in] Progress          A function used report the progress of the
+                               firmware update.  This is an optional parameter
+                               that may be NULL.
+  @param[in] StartPercentage   The start completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+  @param[in] EndPercentage     The end completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWriteWithProgress (
+  IN PLATFORM_FIRMWARE_TYPE                         FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS                           FlashAddress,
+  IN FLASH_ADDRESS_TYPE                             FlashAddressType,
+  IN VOID                                           *Buffer,
+  IN UINTN                                          Length,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,        OPTIONAL
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  )
+{
+  UINT32 ImageType;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  /*
+   * As per the design of firmware capsule, the Firmware Descriptor File
+   * Volume which is used to provide description of firmware update is
+   * attached at the beginning of the firmware file. It must be removed
+   * before writing.
+   */
+  if (Length <= FIRMWARE_DESCRIPTOR_SIZE) {
+    DEBUG ((DEBUG_ERROR, "%a %d The length of firmware image is invalid.\n",
+            __FUNCTION__, __LINE__));
+    return EFI_INVALID_PARAMETER;
+  }
+  Length -= FIRMWARE_DESCRIPTOR_SIZE;
+  Buffer += FIRMWARE_DESCRIPTOR_SIZE;
+
+  ImageType = FirmwareType - FIRMWARE_TYPE_OEM_OFFSET;
+  if (ImageType >= FWU_IMG_TYPE_MAX) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return MmFlashUpdate (
+           ImageType,
+           Buffer,
+           Length,
+           Progress,
+           StartPercentage,
+           EndPercentage
+           );
+}
+
+/**
+  Perform flash write operation.
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWrite (
+  IN PLATFORM_FIRMWARE_TYPE       FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS         FlashAddress,
+  IN FLASH_ADDRESS_TYPE           FlashAddressType,
+  IN VOID                         *Buffer,
+  IN UINTN                        Length
+  )
+{
+  return PerformFlashWriteWithProgress (
+           FirmwareType,
+           FlashAddress,
+           FlashAddressType,
+           Buffer,
+           Length,
+           NULL,
+           0,
+           0
+           );
+}
-- 
2.17.1


  parent reply	other threads:[~2020-12-09  9:24 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-09  9:24 [edk2-platforms][PATCH 00/34] Add new Ampere Mt. Jade platform Nhi Pham
2020-12-09  9:24 ` [edk2-platforms][PATCH 01/34] Initial support for Ampere Altra and " Nhi Pham
2021-01-07 23:57   ` [edk2-devel] " Leif Lindholm
2021-01-15  4:59     ` Vu Nguyen
2020-12-09  9:24 ` [edk2-platforms][PATCH 02/34] Platform/Ampere: Implement FailSafe library Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 03/34] Platform/Ampere: Add FailSafe and WDT support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 04/34] AmpereAltraPkg: Implement GpioLib and I2cLib modules Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 05/34] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 06/34] Platform/Ampere: Add AcpiPccLib to support ACPI PCCT Table Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 07/34] Platform/Ampere: Add AcpiHelperLib to update ACPI DSDT table Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 08/34] JadePkg: Initial support for static ACPI tables Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 09/34] JadePkg: Install some ACPI tables at runtime Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 10/34] Silicon/Ampere: Support Non Volatile storage for Variable service Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 11/34] Silicon/Ampere: Support PlatformManagerUiLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 12/34] AmpereAltraPkg: Add PcieCore Library Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 13/34] AmpereAltraPkg: Add PciHostBridge driver Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 14/34] JadePkg: Add implementation for PcieBoardLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 15/34] JadePkg: Enable PCIe support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 16/34] JadePkg: Add ASpeed GOP driver Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 17/34] Silicon/Ampere: Add Random Number Generator Support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 18/34] Silicon/Ampere: Fixup runtime memory attribute Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 19/34] JadePkg: Add SMBIOS tables support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 20/34] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 21/34] Silicon/Ampere: Add platform info screen Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 22/34] Silicon/Ampere: Add Memory " Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 23/34] AmpereAltraPkg: Add CPU Configuration for SubNUMA Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 24/34] AmpereAltraPkg: Add ACPI configuration screen Nhi Pham
2020-12-09  9:25 ` Nhi Pham [this message]
2020-12-09  9:25 ` [edk2-platforms][PATCH 26/34] JadePkg: Add implementation for UEFI Capsule Update Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 27/34] JadePkg: Add Capsule Update support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 28/34] Silicon/Ampere: Implement PlatformBootManagerLib for LinuxBoot Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 29/34] Platform/Ampere: Add LinuxBoot image Nhi Pham
2020-12-10 12:40   ` [edk2-devel] " Leif Lindholm
2020-12-11  2:38     ` Nhi Pham
2020-12-11 11:15       ` Leif Lindholm
2020-12-09  9:25 ` [edk2-platforms][PATCH 30/34] JadePkg: Support LinuxBoot DSC/FDF build for Jade platform Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 31/34] AmpereAltraPkg: Add BootProgress support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 32/34] JadePkg: Add ACPI/APEI tables Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 33/34] Platform/Ampere: Add AcpiApeiLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 34/34] AmpereAltraPkg, JadePkg: Add RAS setting screen Nhi Pham

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201209092531.30867-26-nhi@os.amperecomputing.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox