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 <suni...@ventanamicro.com> Cc: Leif Lindholm <quic_llind...@quicinc.com> Cc: Michael D Kinney <michael.d.kin...@intel.com> Cc: Li Yong <yong...@intel.com> Signed-off-by: John Chew <yuinyee.c...@starfivetech.com> Acked-by: Sunil V L <suni...@ventanamicro.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 (#110590): https://edk2.groups.io/g/devel/message/110590 Mute This Topic: https://groups.io/mt/102357020/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-