[edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol

John Chew yuinyee.chew at starfivetech.com
Mon Oct 23 07:18:50 UTC 2023


Support for efi variable to store in QSPI flash.
This driver is responsible to initialize both QSPI and Flash driver.

Firmware Volume(FV) Initialization:
	1. Copy flash content into allocated shadow buffer (RAM)
	2. Check FV header validity
	3. If not valid, erase flash based on the region defined in PCDs
           , else skip
	4. If erased, write flash with new FV header, else skip
EFI Variable read:
	1. Read anbd return the content from the shadow buffer (RAM)
EFI Variable write:
	1. Write the data into flash
	2. Update shadow buffer (RAM)

Cc: Sunil V L <sunilvl at ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol at quicinc.com>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Cc: Li Yong <yong.li at intel.com>
Signed-off-by: John Chew <yuinyee.chew at starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c   | 909 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h   | 138 +++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf |  70 ++
 3 files changed, 1117 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
new file mode 100644
index 000000000000..c30e82ed0871
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
@@ -0,0 +1,909 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#include "FvbDxe.h"

+

+STATIC FVB_DEVICE  *mFvbDevice;

+

+STATIC CONST FVB_DEVICE  mFvbFlashInstanceTemplate = {

+  {

+    0,    /* AddrSize ... NEED TO BE FILLED */

+    NULL, /* Read from NOR FLASH ... NEED TO BE FILLED */

+    0,    /* RegBase ... NEED TO BE FILLED */

+    0,    /* AbhBase ... NEED TO BE FILLED */

+    0,    /* FifoWidth ... NEED TO BE FILLED */

+    0,    /* WriteDelay ... NEED TO BE FILLED */

+  }, /* SPI_DEVICE_PARAMS */

+

+  NULL, /* SpiFlashProtocol ... NEED TO BE FILLED */

+  NULL, /* SpiMasterProtocol ... NEED TO BE FILLED */

+  NULL, /* Handle ... NEED TO BE FILLED */

+

+  FVB_FLASH_SIGNATURE, /* Signature ... NEED TO BE FILLED */

+

+  0,     /* ShadowBufBaseAddr ... NEED TO BE FILLED */

+  0,     /* ShadowBufSize ... NEED TO BE FILLED */

+  0,     /* FvbFlashVarOffset ... NEED TO BE FILLED */

+  0,     /* FvbFlashVarSize ... NEED TO BE FILLED */

+  0,     /* BlockSize ... NEED TO BE FILLED */

+  0,     /* LastBlock ... NEED TO BE FILLED */

+  0,     /* StartLba */

+

+  {

+    FvbGetAttributes,       /* GetAttributes */

+    FvbSetAttributes,       /* SetAttributes */

+    FvbGetPhysicalAddress,  /* GetPhysicalAddress */

+    FvbGetBlockSize,        /* GetBlockSize */

+    FvbRead,                /* Read */

+    FvbWrite,               /* Write */

+    FvbEraseBlocks,         /* EraseBlocks */

+    NULL,                   /* ParentHandle */

+  }, /* EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL */

+

+  {

+    {

+      {

+        HARDWARE_DEVICE_PATH,

+        HW_VENDOR_DP,

+        {

+          (UINT8)sizeof (VENDOR_DEVICE_PATH),

+          (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)

+        }

+      },

+      { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 }

+      }

+    },

+    {

+      END_DEVICE_PATH_TYPE,

+      END_ENTIRE_DEVICE_PATH_SUBTYPE,

+      { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }

+    }

+  } /* FVB_DEVICE_PATH */

+};

+

+STATIC

+EFI_STATUS

+FvbInitFvAndVariableStoreHeaders (

+  IN FVB_DEVICE  *FlashInstance

+  )

+{

+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;

+  VARIABLE_STORE_HEADER       *VariableStoreHeader;

+  EFI_STATUS                  Status;

+  VOID                        *Headers;

+  UINTN                       HeadersLength;

+  UINTN                       BlockSize;

+

+  HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +

+                  sizeof (EFI_FV_BLOCK_MAP_ENTRY) +

+                  sizeof (VARIABLE_STORE_HEADER);

+  Headers = AllocateZeroPool (HeadersLength);

+

+  BlockSize = FlashInstance->BlockSize;

+

+  /* VariableBase -> FtwWOrkingBase -> FtwSpareBase are declared

+   * consecutively in contiguous memory

+   */

+  ASSERT (

+          PcdGet64 (PcdFlashNvStorageVariableBase64) +

+          PcdGet32 (PcdFlashNvStorageVariableSize) ==

+          PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)

+          );

+  ASSERT (

+          PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) +

+          PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==

+          PcdGet64 (PcdFlashNvStorageFtwSpareBase64)

+          );

+

+  /* Ensure the size of the variable area is at least one block size */

+  ASSERT (

+          (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&

+          (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)

+          );

+  ASSERT (

+          (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&

+          (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)

+          );

+  ASSERT (

+          (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&

+          (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)

+          );

+

+  /* Ensure the Variable areas are aligned on block size boundaries */

+  ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % BlockSize) == 0);

+  ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) == 0);

+  ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) == 0);

+

+  /* ---------------------------------------------

+   * | Firmware Volume Header |                  |

+   * --------------------------   Non-Volatile   |

+   * | Variable Store Header  | Storage Variable |

+   * --------------------------      Region      |

+   * |       Variables        |                  |

+   * ---------------------------------------------

+   */

+

+  /* Prepare Firmware Volume Header */

+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;

+  CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);

+  FirmwareVolumeHeader->FvLength   = FlashInstance->FvbFlashVarSize;

+  FirmwareVolumeHeader->Signature  = EFI_FVH_SIGNATURE;

+  FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP | /* Reads may be enabled */

+                                     EFI_FVB2_READ_STATUS |      /* Reads are currently enabled */

+                                     EFI_FVB2_STICKY_WRITE |     /* A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY */

+                                     EFI_FVB2_ERASE_POLARITY |   /* After erasure all bits take this value (i.e. '1') */

+                                     EFI_FVB2_WRITE_STATUS |     /* Writes are currently enabled */

+                                     EFI_FVB2_WRITE_ENABLED_CAP; /* Writes may be enabled */

+

+  FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +

+                                       sizeof (EFI_FV_BLOCK_MAP_ENTRY);

+  FirmwareVolumeHeader->Revision              = EFI_FVH_REVISION;

+  FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->LastBlock + 1;

+  FirmwareVolumeHeader->BlockMap[0].Length    = FlashInstance->BlockSize;

+  FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;

+  FirmwareVolumeHeader->BlockMap[1].Length    = 0;

+  FirmwareVolumeHeader->Checksum              = CalculateCheckSum16 (

+                                                                     (UINT16 *)FirmwareVolumeHeader,

+                                                                     FirmwareVolumeHeader->HeaderLength

+                                                                     );

+

+  /* Prepare Variable Store Header */

+  VariableStoreHeader = (VOID *)((UINTN)Headers +

+                                 FirmwareVolumeHeader->HeaderLength);

+  CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);

+  VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -

+                              FirmwareVolumeHeader->HeaderLength;

+  VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;

+  VariableStoreHeader->State  = VARIABLE_STORE_HEALTHY;

+

+  /* Write both header to the flash device on the base address of the

+   * declared variable base address in the flash. CAUTIONS! This will

+   * replace the existing firmware volume and variable header or possibly

+   * cause data corruption. Make sure the declared base address and size

+   * in the flash is only use for EFI Variable Storage.

+   * Offset = 0, LastBlockAdress = 0;

+   */

+  Status = FvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers);

+

+  FreePool (Headers);

+

+  return Status;

+}

+

+STATIC

+EFI_STATUS

+FvbValidateFvHeader (

+  IN  FVB_DEVICE  *FlashInstance

+  )

+{

+  UINT16                      Checksum;

+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;

+  VARIABLE_STORE_HEADER       *VariableStoreHeader;

+  UINTN                       VariableStoreLength;

+

+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;

+

+  /* Verify the header revision, header signature, length from the flash */

+  if ((FirmwareVolumeHeader->Revision  != EFI_FVH_REVISION) ||

+      (FirmwareVolumeHeader->Signature != EFI_FVH_SIGNATURE) ||

+      (FirmwareVolumeHeader->FvLength  != FlashInstance->FvbFlashVarSize))

+  {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): No Firmware Volume header present\n",

+            __func__)

+           );

+    return EFI_NOT_FOUND;

+  }

+

+  /* Verify the Firmware Volume Guid from the flash */

+  if (!CompareGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Firmware Volume Guid non-compatible\n",

+            __func__)

+           );

+    return EFI_NOT_FOUND;

+  }

+

+  /* Verify the header checksum from the flash */

+  Checksum = CalculateSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);

+  if (Checksum != 0) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): FV checksum is invalid (Checksum:0x%x)\n",

+            __func__,

+            Checksum)

+           );

+    return EFI_NOT_FOUND;

+  }

+

+  VariableStoreHeader = (VOID *)((UINTN)FirmwareVolumeHeader + FirmwareVolumeHeader->HeaderLength);

+

+  /* Verify the Variable Store Guid */

+  if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&

+      !CompareGuid (

+                    &VariableStoreHeader->Signature,

+                    &gEfiAuthenticatedVariableGuid

+                    ))

+  {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Variable Store Guid non-compatible\n",

+            __func__)

+           );

+    return EFI_NOT_FOUND;

+  }

+

+  /* Verify the actual Variable Store length with declare size in header*/

+  VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -

+                        FirmwareVolumeHeader->HeaderLength;

+  if (VariableStoreHeader->Size != VariableStoreLength) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Variable Store Length does not match\n",

+            __func__)

+           );

+    return EFI_NOT_FOUND;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbGetAttributes (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes

+  )

+{

+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;

+  EFI_FVB_ATTRIBUTES_2        *FlashFvbAttributes;

+  FVB_DEVICE                  *FlashInstance;

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  FirmwareVolumeHeader        = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;

+  FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FirmwareVolumeHeader->Attributes);

+

+  *Attributes = *FlashFvbAttributes;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbSetAttributes (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes

+  )

+{

+  EFI_FVB_ATTRIBUTES_2  OldAttributes;

+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;

+  EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;

+  FVB_DEVICE            *FlashInstance;

+  UINT32                Capabilities;

+  UINT32                OldStatus;

+  UINT32                NewStatus;

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  /* Read current attribute from the Frimware Volume Header */

+  FvbGetAttributes (This, &FlashFvbAttributes);

+

+  OldAttributes = FlashFvbAttributes;

+  Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;

+  OldStatus     = OldAttributes & EFI_FVB2_STATUS;

+  NewStatus     = *Attributes & EFI_FVB2_STATUS;

+

+  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \

+                        EFI_FVB2_READ_ENABLED_CAP   | \

+                        EFI_FVB2_WRITE_DISABLED_CAP | \

+                        EFI_FVB2_WRITE_ENABLED_CAP  | \

+                        EFI_FVB2_LOCK_CAP           | \

+                        EFI_FVB2_STICKY_WRITE       | \

+                        EFI_FVB2_ERASE_POLARITY     | \

+                        EFI_FVB2_READ_LOCK_CAP      | \

+                        EFI_FVB2_WRITE_LOCK_CAP     | \

+                        EFI_FVB2_ALIGNMENT;

+

+  /* Some attributes of FV is read only can *not* be set */

+  if ((OldAttributes & UnchangedAttributes) ^

+      (*Attributes & UnchangedAttributes))

+  {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  /* If firmware volume is locked, no status bit can be updated */

+  if (OldAttributes & EFI_FVB2_LOCK_STATUS) {

+    if (OldStatus ^ NewStatus) {

+      return EFI_ACCESS_DENIED;

+    }

+  }

+

+  /*  Test read disable */

+  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {

+    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  /* Test read enable */

+  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {

+    if (NewStatus & EFI_FVB2_READ_STATUS) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  /* Test write disable */

+  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {

+    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  /* Test write enable */

+  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {

+    if (NewStatus & EFI_FVB2_WRITE_STATUS) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  /* Test lock */

+  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {

+    if (NewStatus & EFI_FVB2_LOCK_STATUS) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));

+  FlashFvbAttributes = FlashFvbAttributes | NewStatus;

+  *Attributes        = FlashFvbAttributes;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbGetPhysicalAddress (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  OUT       EFI_PHYSICAL_ADDRESS                 *Address

+  )

+{

+  FVB_DEVICE  *FlashInstance;

+

+  ASSERT (Address != NULL);

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  /* Do not support MMIO, return the shadow buffer instead */

+  *Address = FlashInstance->ShadowBufBaseAddr;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbGetBlockSize (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  OUT       UINTN                                *BlockSize,

+  OUT       UINTN                                *NumberOfBlocks

+  )

+{

+  FVB_DEVICE  *FlashInstance;

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  if (Lba > FlashInstance->LastBlock) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Error: Requested LBA %ld is beyond the last available LBA (%ld).\n",

+            __func__,

+            Lba,

+            FlashInstance->LastBlock)

+           );

+    return EFI_INVALID_PARAMETER;

+  } else {

+    /* Assume equal sized blocks in all flash devices */

+    *BlockSize      = (UINTN)FlashInstance->BlockSize;

+    *NumberOfBlocks = (UINTN)(FlashInstance->LastBlock - Lba + 1);

+

+    return EFI_SUCCESS;

+  }

+}

+

+EFI_STATUS

+EFIAPI

+FvbRead (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  IN        UINTN                                Offset,

+  IN OUT    UINTN                                *NumBytes,

+  IN OUT    UINT8                                *Buffer

+  )

+{

+  FVB_DEVICE  *FlashInstance;

+  UINTN       BlockSize;

+  UINTN       DataOffset;

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  /* Cache the block size to avoid de-referencing pointers all the time */

+  BlockSize = FlashInstance->BlockSize;

+

+  /* Offset + byte have to be within the define block size.

+   * The read must not span block boundaries. We need to

+   * check each variable individually because adding two

+   * large values together migght cause overflows.

+   */

+  if ((Offset               >= BlockSize) ||

+      (*NumBytes            >  BlockSize) ||

+      ((Offset + *NumBytes) >  BlockSize))

+  {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",

+            __func__,

+            Offset,

+            *NumBytes,

+            BlockSize)

+           );

+    return EFI_BAD_BUFFER_SIZE;

+  }

+

+  /* No bytes to read */

+  if (*NumBytes == 0) {

+    return EFI_SUCCESS;

+  }

+

+  DataOffset = GET_DATA_OFFSET (

+                                FlashInstance->ShadowBufBaseAddr + Offset,

+                                FlashInstance->StartLba + Lba,

+                                FlashInstance->BlockSize

+                                );

+

+  /* Copy variable from the shadow buffer */

+  CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbWrite (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  IN        UINTN                                Offset,

+  IN OUT    UINTN                                *NumBytes,

+  IN        UINT8                                *Buffer

+  )

+{

+  EFI_STATUS  Status;

+  FVB_DEVICE  *FlashInstance;

+  UINTN       DataOffset;

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  DataOffset = GET_DATA_OFFSET (

+                                FlashInstance->FvbFlashVarOffset + Offset,

+                                FlashInstance->StartLba + Lba,

+                                FlashInstance->BlockSize

+                                );

+

+  Status = FlashInstance->SpiFlashProtocol->Write (

+                                                   &FlashInstance->SpiDevice,

+                                                   DataOffset,

+                                                   *NumBytes,

+                                                   Buffer

+                                                   );

+  if (EFI_ERROR (Status)) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Failed to write to Spi device\n",

+            __func__)

+           );

+    return Status;

+  }

+

+  DataOffset = GET_DATA_OFFSET (

+                                FlashInstance->ShadowBufBaseAddr + Offset,

+                                FlashInstance->StartLba + Lba,

+                                FlashInstance->BlockSize

+                                );

+

+  /* Update shadow buffer */

+  CopyMem ((UINTN *)DataOffset, Buffer, *NumBytes);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+FvbEraseBlocks (

+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  ...

+  )

+{

+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;

+  FVB_DEVICE            *FlashInstance;

+  EFI_STATUS            Status;

+  VA_LIST               Args;

+  UINTN                 BlockAddress;  /* Physical address of Lba to erase */

+  EFI_LBA               StartingLba;   /* Lba from which we start erasing */

+  UINTN                 NumOfLba;      /* Number of Lba blocks to erase */

+

+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);

+

+  Status = EFI_SUCCESS;

+

+  /* Detect WriteDisabled state */

+  FvbGetAttributes (This, &FlashFvbAttributes);

+  if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Device is in WriteDisabled state.\n",

+            __func__)

+           );

+    return EFI_ACCESS_DENIED;

+  }

+

+  /*

+   * Before erasing, check the entire list of parameters to ensure

+   * all specified blocks are valid.

+  */

+  VA_START (Args, This);

+  do {

+    /* Get the Lba from which we start erasing */

+    StartingLba = VA_ARG (Args, EFI_LBA);

+

+    /* Have we reached the end of the list? */

+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {

+      break;

+    }

+

+    /* How many Lba blocks are we requested to erase? */

+    NumOfLba = VA_ARG (Args, UINT32);

+

+    /* All blocks must be within range */

+    if ((NumOfLba == 0) ||

+        ((FlashInstance->StartLba + StartingLba + NumOfLba - 1) >

+         FlashInstance->LastBlock))

+    {

+      DEBUG (

+             (DEBUG_ERROR,

+              "%a(): Error: Requested LBA are beyond the last available LBA (%ld).\n",

+              __func__,

+              FlashInstance->LastBlock)

+             );

+

+      VA_END (Args);

+

+      return EFI_INVALID_PARAMETER;

+    }

+  } while (TRUE);

+

+  VA_END (Args);

+

+  /* Start erasing */

+  VA_START (Args, This);

+  do {

+    /* Get the Lba from which we start erasing */

+    StartingLba = VA_ARG (Args, EFI_LBA);

+

+    /* Have we reached the end of the list? */

+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {

+      break;

+    }

+

+    /* How many Lba blocks are we requested to erase? */

+    NumOfLba = VA_ARG (Args, UINT32);

+

+    /* Go through each requested block and erase it */

+    while (NumOfLba > 0) {

+      /* Get the offset address of Lba to erase */

+      BlockAddress = GET_DATA_OFFSET (

+                                      FlashInstance->FvbFlashVarOffset,

+                                      FlashInstance->StartLba + StartingLba,

+                                      FlashInstance->BlockSize

+                                      );

+

+      /* Erase single block */

+      Status = FlashInstance->SpiFlashProtocol->Erase (

+                                                       &FlashInstance->SpiDevice,

+                                                       BlockAddress,

+                                                       FlashInstance->BlockSize

+                                                       );

+      if (EFI_ERROR (Status)) {

+        VA_END (Args);

+        return EFI_DEVICE_ERROR;

+      }

+

+      StartingLba++;

+      NumOfLba--;

+    }

+  } while (TRUE);

+

+  VA_END (Args);

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+EFI_STATUS

+FvbFlashProbe (

+  IN FVB_DEVICE  *FlashInstance

+  )

+{

+  SPI_FLASH_PROTOCOL  *SpiFlashProtocol;

+  EFI_STATUS          Status;

+

+  SpiFlashProtocol = FlashInstance->SpiFlashProtocol;

+

+  /* Read SPI flash ID */

+  Status = SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE);

+  if (EFI_ERROR (Status)) {

+    return EFI_NOT_FOUND;

+  }

+

+  Status = SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->SpiDevice);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot initialize flash device\n", __func__));

+    return EFI_DEVICE_ERROR;

+  }

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+EFI_STATUS

+FvbPrepareFvHeader (

+  IN FVB_DEVICE  *FlashInstance

+  )

+{

+  EFI_BOOT_MODE  BootMode;

+  EFI_STATUS     Status;

+

+  /* Check if it is required to use default environment */

+  BootMode = GetBootModeHob ();

+  if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {

+    Status = EFI_INVALID_PARAMETER;

+  } else {

+    /* Validate header at the beginning of FV region */

+    Status = FvbValidateFvHeader (FlashInstance);

+  }

+

+  /* Install the default FVB header if required */

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): The FVB Header is not valid.\n", __func__));

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Installing a correct one for this volume.\n",

+            __func__)

+           );

+

+    /* Erase entire region that is reserved for variable storage in flash */

+    Status = FlashInstance->SpiFlashProtocol->Erase (

+                                                     &FlashInstance->SpiDevice,

+                                                     FlashInstance->FvbFlashVarOffset,

+                                                     FlashInstance->FvbFlashVarSize

+                                                     );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    /* Write a new firmware volume and varaible storage headers */

+    Status = FvbInitFvAndVariableStoreHeaders (FlashInstance);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+EFI_STATUS

+FvbConfigureFlashInstance (

+  IN OUT FVB_DEVICE  *FlashInstance

+  )

+{

+  EFI_STATUS  Status;

+  UINTN       DataOffset;

+  UINTN       VariableSize, FtwWorkingSize, FtwSpareSize, MemorySize;

+

+  Status = gBS->LocateProtocol (

+                                &gJH7110SpiFlashProtocolGuid,

+                                NULL,

+                                (VOID **)&FlashInstance->SpiFlashProtocol

+                                );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiFlash protocol\n", __func__));

+    return Status;

+  }

+

+  Status = gBS->LocateProtocol (

+                                &gJH7110SpiMasterProtocolGuid,

+                                NULL,

+                                (VOID **)&FlashInstance->SpiMasterProtocol

+                                );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiMaster protocol\n", __func__));

+    return Status;

+  }

+

+  /* Setup and probe SPI flash */

+  FlashInstance->SpiMasterProtocol->SetupDevice (

+                                                 FlashInstance->SpiMasterProtocol,

+                                                 &FlashInstance->SpiDevice

+                                                 );

+  Status = FvbFlashProbe (FlashInstance);

+  if (EFI_ERROR (Status)) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Error while performing SPI flash probe\n",

+            __func__)

+           );

+    return Status;

+  }

+

+  /* Fill remaining flash description */

+  VariableSize   = PcdGet32 (PcdFlashNvStorageVariableSize);

+  FtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);

+  FtwSpareSize   = PcdGet32 (PcdFlashNvStorageFtwSpareSize);

+

+  FlashInstance->FvbFlashVarSize    = VariableSize + FtwWorkingSize + FtwSpareSize;

+  FlashInstance->FvbFlashVarOffset  = PcdGet32(PcdJH7110FlashVarOffset);

+  FlashInstance->BlockSize = FlashInstance->SpiDevice.Info->SectorSize;

+  FlashInstance->LastBlock = (FlashInstance->FvbFlashVarSize /

+                                   FlashInstance->BlockSize) - 1;

+  FlashInstance->ShadowBufSize = FlashInstance->FvbFlashVarSize;

+

+  /* Allocate memory for shadow buffer */

+  MemorySize = EFI_SIZE_TO_PAGES (FlashInstance->FvbFlashVarSize);

+

+  /* FaultTolerantWriteDxe requires memory to be aligned to FtwWorkingSize */

+  FlashInstance->ShadowBufBaseAddr = (UINTN)AllocateAlignedRuntimePages (

+                                                                          MemorySize,

+                                                                          SIZE_64KB

+                                                                          );

+  if (FlashInstance->ShadowBufBaseAddr == (UINTN)NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  /* Update PCDs value according to allocated memory */

+  Status = PcdSet64S (

+                      PcdFlashNvStorageVariableBase64,

+                      (UINT64)FlashInstance->ShadowBufBaseAddr

+                      );

+  ASSERT_EFI_ERROR (Status);

+  Status = PcdSet64S (

+                      PcdFlashNvStorageFtwWorkingBase64,

+                      (UINT64)FlashInstance->ShadowBufBaseAddr

+                      + VariableSize

+                      );

+  ASSERT_EFI_ERROR (Status);

+  Status = PcdSet64S (

+                      PcdFlashNvStorageFtwSpareBase64,

+                      (UINT64)FlashInstance->ShadowBufBaseAddr

+                      + VariableSize

+                      + FtwWorkingSize

+                      );

+  ASSERT_EFI_ERROR (Status);

+

+  /* ill the shadow buffer with data from flash */

+  DataOffset = GET_DATA_OFFSET (

+                                FlashInstance->FvbFlashVarOffset,

+                                FlashInstance->StartLba,

+                                FlashInstance->BlockSize

+                                );

+  Status = FlashInstance->SpiFlashProtocol->Read (

+                                                  &FlashInstance->SpiDevice,

+                                                  DataOffset,

+                                                  FlashInstance->FvbFlashVarSize,

+                                                  (VOID *)FlashInstance->ShadowBufBaseAddr

+                                                  );

+  if (EFI_ERROR (Status)) {

+    goto ErrorFreeAllocatedPages;

+  }

+

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                                                   &FlashInstance->Handle,

+                                                   &gEfiDevicePathProtocolGuid,

+                                                   &FlashInstance->DevicePath,

+                                                   &gEfiFirmwareVolumeBlockProtocolGuid,

+                                                   &FlashInstance->FvbProtocol,

+                                                   NULL

+                                                   );

+  if (EFI_ERROR (Status)) {

+    goto ErrorFreeAllocatedPages;

+  }

+

+  Status = FvbPrepareFvHeader (FlashInstance);

+  if (EFI_ERROR (Status)) {

+    goto ErrorPrepareFvbHeader;

+  }

+

+  return EFI_SUCCESS;

+

+ErrorPrepareFvbHeader:

+  gBS->UninstallMultipleProtocolInterfaces (

+                                            &FlashInstance->Handle,

+                                            &gEfiDevicePathProtocolGuid,

+                                            &gEfiFirmwareVolumeBlockProtocolGuid,

+                                            NULL

+                                            );

+

+ErrorFreeAllocatedPages:

+    FreeAlignedPages (

+                      (VOID *)FlashInstance->ShadowBufBaseAddr,

+                      MemorySize

+                      );

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+FvbEntryPoint (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS  Status;

+

+  /* Allocate memory for FVB flash device*/

+  mFvbDevice = AllocateRuntimeCopyPool (

+                                        sizeof (mFvbFlashInstanceTemplate),

+                                        &mFvbFlashInstanceTemplate

+                                        );

+  if (mFvbDevice == NULL) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  /* Detect and configure flash device */

+  Status = FvbConfigureFlashInstance (mFvbDevice);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Fail to configure Fvb SPI device\n", __func__));

+    goto ErrorConfigureFlash;

+  }

+

+  /* The driver implementing the variable read service can now be dispatched;

+   * the varstore headers are in place.

+   */

+  Status = gBS->InstallProtocolInterface (

+                                          &gImageHandle,

+                                          &gEdkiiNvVarStoreFormattedGuid,

+                                          EFI_NATIVE_INTERFACE,

+                                          NULL

+                                          );

+  if (EFI_ERROR (Status)) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a(): Failed to install gEdkiiNvVarStoreFormattedGuid\n",

+            __func__)

+           );

+    goto ErrorInstallNvVarStoreFormatted;

+  }

+

+  return Status;

+

+ErrorInstallNvVarStoreFormatted:

+  gBS->UninstallMultipleProtocolInterfaces (

+                                            &mFvbDevice->Handle,

+                                            &gEfiDevicePathProtocolGuid,

+                                            &gEfiFirmwareVolumeBlockProtocolGuid,

+                                            NULL

+                                            );

+

+ErrorConfigureFlash:

+  FreePool (mFvbDevice);

+

+  return Status;

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
new file mode 100644
index 000000000000..6b0450b17275
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
@@ -0,0 +1,138 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#ifndef __FVB_DXE_H__

+#define __FVB_DXE_H__

+

+#include <PiDxe.h>

+

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/DxeServicesTableLib.h>

+#include <Library/HobLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/PcdLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiLib.h>

+#include <Library/UefiRuntimeLib.h>

+

+#include <Guid/NvVarStoreFormatted.h>

+#include <Guid/SystemNvDataGuid.h>

+#include <Guid/VariableFormat.h>

+

+#include <Protocol/BlockIo.h>

+#include <Protocol/FirmwareVolumeBlock.h>

+#include <Protocol/Spi.h>

+#include <Protocol/SpiFlash.h>

+

+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize)  ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))

+

+#define FVB_FLASH_SIGNATURE  SIGNATURE_32('S', 'n', 'o', 'r')

+#define INSTANCE_FROM_FVB_THIS(a)  CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)

+

+//

+// Define two helper macro to extract the Capability field or Status field in FVB

+// bit fields.

+//

+#define EFI_FVB2_CAPABILITIES  (EFI_FVB2_READ_DISABLED_CAP |\

+                               EFI_FVB2_READ_ENABLED_CAP | \

+                               EFI_FVB2_WRITE_DISABLED_CAP | \

+                               EFI_FVB2_WRITE_ENABLED_CAP | \

+                               EFI_FVB2_LOCK_CAP)

+

+#define EFI_FVB2_STATUS  (EFI_FVB2_READ_STATUS |      \

+                          EFI_FVB2_WRITE_STATUS | \

+                          EFI_FVB2_LOCK_STATUS)

+

+typedef struct {

+  VENDOR_DEVICE_PATH          Vendor;

+  EFI_DEVICE_PATH_PROTOCOL    End;

+} FVB_DEVICE_PATH;

+

+typedef struct {

+  SPI_DEVICE_PARAMS                      SpiDevice;

+

+  SPI_FLASH_PROTOCOL                     *SpiFlashProtocol;

+  SPI_MASTER_PROTOCOL                    *SpiMasterProtocol;

+

+  EFI_HANDLE                             Handle;

+

+  UINT32                                 Signature;

+

+  UINTN                                  ShadowBufBaseAddr;

+  UINTN                                  ShadowBufSize;

+  UINTN                                  FvbFlashVarOffset;

+  UINTN                                  FvbFlashVarSize;

+  UINTN                                  BlockSize;

+  UINTN                                  LastBlock;

+  EFI_LBA                                StartLba;

+

+  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;

+

+  FVB_DEVICE_PATH                        DevicePath;

+} FVB_DEVICE;

+

+EFI_STATUS

+EFIAPI

+FvbGetAttributes (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes

+  );

+

+EFI_STATUS

+EFIAPI

+FvbSetAttributes (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes

+  );

+

+EFI_STATUS

+EFIAPI

+FvbGetPhysicalAddress (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  OUT       EFI_PHYSICAL_ADDRESS                 *Address

+  );

+

+EFI_STATUS

+EFIAPI

+FvbGetBlockSize (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  OUT       UINTN                                *BlockSize,

+  OUT       UINTN                                *NumberOfBlocks

+  );

+

+EFI_STATUS

+EFIAPI

+FvbRead (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  IN        UINTN                                Offset,

+  IN OUT    UINTN                                *NumBytes,

+  IN OUT    UINT8                                *Buffer

+  );

+

+EFI_STATUS

+EFIAPI

+FvbWrite (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  IN        EFI_LBA                              Lba,

+  IN        UINTN                                Offset,

+  IN OUT    UINTN                                *NumBytes,

+  IN        UINT8                                *Buffer

+  );

+

+EFI_STATUS

+EFIAPI

+FvbEraseBlocks (

+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,

+  ...

+  );

+

+#endif //__FVB_DXE_H__

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
new file mode 100644
index 000000000000..715989bfcc2b
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
@@ -0,0 +1,70 @@
+## @file

+#

+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x0001001A

+  BASE_NAME                      = FvbDxe

+  FILE_GUID                      = DB8BFC83-6DEA-4AD1-AD3D-FDC579430233

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 0.1

+  ENTRY_POINT                    = FvbEntryPoint

+

+[Sources]

+  FvbDxe.c

+

+[Packages]

+  ArmPlatformPkg/ArmPlatformPkg.dec

+  EmbeddedPkg/EmbeddedPkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  MdePkg/MdePkg.dec

+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  DevicePathLib

+  DxeServicesTableLib

+  HobLib

+  IoLib

+  MemoryAllocationLib

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  UefiLib

+  UefiRuntimeLib

+  UefiRuntimeServicesTableLib

+

+[Guids]

+  gEdkiiNvVarStoreFormattedGuid

+  gEfiAuthenticatedVariableGuid

+  gEfiEventVirtualAddressChangeGuid

+  gEfiSystemNvDataFvGuid

+  gEfiVariableGuid

+

+[Protocols]

+  gEfiDevicePathProtocolGuid

+  gEfiFirmwareVolumeBlockProtocolGuid

+  gJH7110SpiFlashProtocolGuid

+  gJH7110SpiMasterProtocolGuid

+

+[FixedPcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize

+  gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64

+

+[Depex]

+  gEfiCpuArchProtocolGuid AND

+  gJH7110SpiMasterProtocolGuid AND

+  gJH7110SpiFlashProtocolGuid

-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109898): https://edk2.groups.io/g/devel/message/109898
Mute This Topic: https://groups.io/mt/102130707/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