From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 93A38AC0E9B for ; Mon, 23 Oct 2023 07:19:52 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=WwUEsaHI9y6LRDnqQ2nxI8jFEGOEljgEgjgoS+dnWEU=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1698045591; v=1; b=gULLgEmGqK1hsqAWrtbnwsjtp7cSW1QWs8+iyMUvR3ndZ5Givh1WNmx3z+6NFzQuD7ufWUvT ZgoV801dL86pL6UMuAjg21gPbPqNyp8SWjJVHPnSqIiBW0WeLNxj7QaLGncwOkifQuJnpbDt474 y3YjkpKmf9B46krCbfdzqm3o= X-Received: by 127.0.0.2 with SMTP id ZhicYY7687511xFt4f6Ikvc3; Mon, 23 Oct 2023 00:19:51 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web10.115228.1698045582214444831 for ; Mon, 23 Oct 2023 00:19:50 -0700 X-Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id 7BD7A24E383; Mon, 23 Oct 2023 15:19:38 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:38 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:35 +0800 From: "John Chew" To: CC: John Chew , Sunil V L , Leif Lindholm , Michael D Kinney , "Cc : Li Yong" Subject: [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol Date: Mon, 23 Oct 2023 15:18:50 +0800 Message-ID: <20231023071851.813-4-yuinyee.chew@starfivetech.com> In-Reply-To: <20231023071851.813-1-yuinyee.chew@starfivetech.com> References: <20231023071851.813-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS066.cuchost.com (172.16.6.26) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: Lyn39sw2qpVrOPu6mFCrmVNWx7686176AA= Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=gULLgEmG; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io 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 Cc: Leif Lindholm Cc: Michael D Kinney Cc: Cc: Li Yong Signed-off-by: John Chew --- Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c | 90= 9 ++++++++++++++++++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h | 13= 8 +++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf | 7= 0 ++ 3 files changed, 1117 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/Fvb= Dxe.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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "FvbDxe.h" + +STATIC FVB_DEVICE *mFvbDevice; + +STATIC CONST FVB_DEVICE mFvbFlashInstanceTemplate =3D { + { + 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 =3D sizeof (EFI_FIRMWARE_VOLUME_HEADER) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + + sizeof (VARIABLE_STORE_HEADER); + Headers =3D AllocateZeroPool (HeadersLength); + + BlockSize =3D FlashInstance->BlockSize; + + /* VariableBase -> FtwWOrkingBase -> FtwSpareBase are declared + * consecutively in contiguous memory + */ + ASSERT ( + PcdGet64 (PcdFlashNvStorageVariableBase64) + + PcdGet32 (PcdFlashNvStorageVariableSize) =3D=3D + PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + ); + ASSERT ( + PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) =3D=3D + 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) =3D=3D = 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) =3D= =3D 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) =3D=3D = 0); + + /* --------------------------------------------- + * | Firmware Volume Header | | + * -------------------------- Non-Volatile | + * | Variable Store Header | Storage Variable | + * -------------------------- Region | + * | Variables | | + * --------------------------------------------- + */ + + /* Prepare Firmware Volume Header */ + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Headers; + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid= ); + FirmwareVolumeHeader->FvLength =3D FlashInstance->FvbFlashVarSize; + FirmwareVolumeHeader->Signature =3D EFI_FVH_SIGNATURE; + FirmwareVolumeHeader->Attributes =3D EFI_FVB2_READ_ENABLED_CAP | /* Read= s may be enabled */ + EFI_FVB2_READ_STATUS | /* Reads = are currently enabled */ + EFI_FVB2_STICKY_WRITE | /* A bloc= k 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 =3D sizeof (EFI_FIRMWARE_VOLUME_HEADE= R) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY); + FirmwareVolumeHeader->Revision =3D EFI_FVH_REVISION; + FirmwareVolumeHeader->BlockMap[0].NumBlocks =3D FlashInstance->LastBlock= + 1; + FirmwareVolumeHeader->BlockMap[0].Length =3D FlashInstance->BlockSize= ; + FirmwareVolumeHeader->BlockMap[1].NumBlocks =3D 0; + FirmwareVolumeHeader->BlockMap[1].Length =3D 0; + FirmwareVolumeHeader->Checksum =3D CalculateCheckSum16 ( + (UINT= 16 *)FirmwareVolumeHeader, + Firmw= areVolumeHeader->HeaderLength + ); + + /* Prepare Variable Store Header */ + VariableStoreHeader =3D (VOID *)((UINTN)Headers + + FirmwareVolumeHeader->HeaderLength); + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGui= d); + VariableStoreHeader->Size =3D PcdGet32 (PcdFlashNvStorageVariableSize) - + FirmwareVolumeHeader->HeaderLength; + VariableStoreHeader->Format =3D VARIABLE_STORE_FORMATTED; + VariableStoreHeader->State =3D 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 =3D 0, LastBlockAdress =3D 0; + */ + Status =3D 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 =3D (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->Sh= adowBufBaseAddr; + + /* Verify the header revision, header signature, length from the flash *= / + if ((FirmwareVolumeHeader->Revision !=3D EFI_FVH_REVISION) || + (FirmwareVolumeHeader->Signature !=3D EFI_FVH_SIGNATURE) || + (FirmwareVolumeHeader->FvLength !=3D 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, &gEfiSystemNvDa= taFvGuid)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Firmware Volume Guid non-compatible\n", + __func__) + ); + return EFI_NOT_FOUND; + } + + /* Verify the header checksum from the flash */ + Checksum =3D CalculateSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVol= umeHeader->HeaderLength); + if (Checksum !=3D 0) { + DEBUG ( + (DEBUG_ERROR, + "%a(): FV checksum is invalid (Checksum:0x%x)\n", + __func__, + Checksum) + ); + return EFI_NOT_FOUND; + } + + VariableStoreHeader =3D (VOID *)((UINTN)FirmwareVolumeHeader + FirmwareV= olumeHeader->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 =3D PcdGet32 (PcdFlashNvStorageVariableSize) - + FirmwareVolumeHeader->HeaderLength; + if (VariableStoreHeader->Size !=3D 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 =3D INSTANCE_FROM_FVB_THIS (This); + + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)FlashInsta= nce->ShadowBufBaseAddr; + FlashFvbAttributes =3D (EFI_FVB_ATTRIBUTES_2 *)&(FirmwareVolumeHeader->A= ttributes); + + *Attributes =3D *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 =3D INSTANCE_FROM_FVB_THIS (This); + + /* Read current attribute from the Frimware Volume Header */ + FvbGetAttributes (This, &FlashFvbAttributes); + + OldAttributes =3D FlashFvbAttributes; + Capabilities =3D OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus =3D OldAttributes & EFI_FVB2_STATUS; + NewStatus =3D *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes =3D 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) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test read enable */ + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test write disable */ + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test write enable */ + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test lock */ + if ((Capabilities & EFI_FVB2_LOCK_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + FlashFvbAttributes =3D FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STA= TUS)); + FlashFvbAttributes =3D FlashFvbAttributes | NewStatus; + *Attributes =3D 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 !=3D NULL); + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + /* Do not support MMIO, return the shadow buffer instead */ + *Address =3D 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 =3D INSTANCE_FROM_FVB_THIS (This); + + if (Lba > FlashInstance->LastBlock) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Error: Requested LBA %ld is beyond the last available L= BA (%ld).\n", + __func__, + Lba, + FlashInstance->LastBlock) + ); + return EFI_INVALID_PARAMETER; + } else { + /* Assume equal sized blocks in all flash devices */ + *BlockSize =3D (UINTN)FlashInstance->BlockSize; + *NumberOfBlocks =3D (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 =3D INSTANCE_FROM_FVB_THIS (This); + + /* Cache the block size to avoid de-referencing pointers all the time */ + BlockSize =3D 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 >=3D BlockSize) || + (*NumBytes > BlockSize) || + ((Offset + *NumBytes) > BlockSize)) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): Wrong buffer size: (Offset=3D0x%x + NumBytes=3D0x%x) > = BlockSize=3D0x%x\n", + __func__, + Offset, + *NumBytes, + BlockSize) + ); + return EFI_BAD_BUFFER_SIZE; + } + + /* No bytes to read */ + if (*NumBytes =3D=3D 0) { + return EFI_SUCCESS; + } + + DataOffset =3D 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 =3D INSTANCE_FROM_FVB_THIS (This); + + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->BlockSize + ); + + Status =3D FlashInstance->SpiFlashProtocol->Write ( + &FlashInstance->SpiDevi= ce, + DataOffset, + *NumBytes, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Failed to write to Spi device\n", + __func__) + ); + return Status; + } + + DataOffset =3D 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 =3D INSTANCE_FROM_FVB_THIS (This); + + Status =3D EFI_SUCCESS; + + /* Detect WriteDisabled state */ + FvbGetAttributes (This, &FlashFvbAttributes); + if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) =3D=3D 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 =3D VA_ARG (Args, EFI_LBA); + + /* Have we reached the end of the list? */ + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { + break; + } + + /* How many Lba blocks are we requested to erase? */ + NumOfLba =3D VA_ARG (Args, UINT32); + + /* All blocks must be within range */ + if ((NumOfLba =3D=3D 0) || + ((FlashInstance->StartLba + StartingLba + NumOfLba - 1) > + FlashInstance->LastBlock)) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): Error: Requested LBA are beyond the last available LB= A (%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 =3D VA_ARG (Args, EFI_LBA); + + /* Have we reached the end of the list? */ + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { + break; + } + + /* How many Lba blocks are we requested to erase? */ + NumOfLba =3D VA_ARG (Args, UINT32); + + /* Go through each requested block and erase it */ + while (NumOfLba > 0) { + /* Get the offset address of Lba to erase */ + BlockAddress =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset, + FlashInstance->StartLba + StartingLb= a, + FlashInstance->BlockSize + ); + + /* Erase single block */ + Status =3D FlashInstance->SpiFlashProtocol->Erase ( + &FlashInstance->Spi= Device, + BlockAddress, + FlashInstance->Bloc= kSize + ); + 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 =3D FlashInstance->SpiFlashProtocol; + + /* Read SPI flash ID */ + Status =3D SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status =3D SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->Spi= Device); + 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 =3D GetBootModeHob (); + if (BootMode =3D=3D BOOT_WITH_DEFAULT_SETTINGS) { + Status =3D EFI_INVALID_PARAMETER; + } else { + /* Validate header at the beginning of FV region */ + Status =3D 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 =3D FlashInstance->SpiFlashProtocol->Erase ( + &FlashInstance->SpiDe= vice, + FlashInstance->FvbFla= shVarOffset, + FlashInstance->FvbFla= shVarSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /* Write a new firmware volume and varaible storage headers */ + Status =3D 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 =3D gBS->LocateProtocol ( + &gJH7110SpiFlashProtocolGuid, + NULL, + (VOID **)&FlashInstance->SpiFlashProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiFlash protocol\n", __func= __)); + return Status; + } + + Status =3D gBS->LocateProtocol ( + &gJH7110SpiMasterProtocolGuid, + NULL, + (VOID **)&FlashInstance->SpiMasterProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiMaster protocol\n", __fun= c__)); + return Status; + } + + /* Setup and probe SPI flash */ + FlashInstance->SpiMasterProtocol->SetupDevice ( + FlashInstance->SpiMasterP= rotocol, + &FlashInstance->SpiDevice + ); + Status =3D 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 =3D PcdGet32 (PcdFlashNvStorageVariableSize); + FtwWorkingSize =3D PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + FtwSpareSize =3D PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + FlashInstance->FvbFlashVarSize =3D VariableSize + FtwWorkingSize + Ft= wSpareSize; + FlashInstance->FvbFlashVarOffset =3D PcdGet32(PcdJH7110FlashVarOffset); + FlashInstance->BlockSize =3D FlashInstance->SpiDevice.Info->SectorSize; + FlashInstance->LastBlock =3D (FlashInstance->FvbFlashVarSize / + FlashInstance->BlockSize) - 1; + FlashInstance->ShadowBufSize =3D FlashInstance->FvbFlashVarSize; + + /* Allocate memory for shadow buffer */ + MemorySize =3D EFI_SIZE_TO_PAGES (FlashInstance->FvbFlashVarSize); + + /* FaultTolerantWriteDxe requires memory to be aligned to FtwWorkingSize= */ + FlashInstance->ShadowBufBaseAddr =3D (UINTN)AllocateAlignedRuntimePages = ( + = MemorySize, + = SIZE_64KB + = ); + if (FlashInstance->ShadowBufBaseAddr =3D=3D (UINTN)NULL) { + return EFI_OUT_OF_RESOURCES; + } + + /* Update PCDs value according to allocated memory */ + Status =3D PcdSet64S ( + PcdFlashNvStorageVariableBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + ); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet64S ( + PcdFlashNvStorageFtwWorkingBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + + VariableSize + ); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet64S ( + PcdFlashNvStorageFtwSpareBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + + VariableSize + + FtwWorkingSize + ); + ASSERT_EFI_ERROR (Status); + + /* ill the shadow buffer with data from flash */ + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset, + FlashInstance->StartLba, + FlashInstance->BlockSize + ); + Status =3D FlashInstance->SpiFlashProtocol->Read ( + &FlashInstance->SpiDevic= e, + DataOffset, + FlashInstance->FvbFlashV= arSize, + (VOID *)FlashInstance->S= hadowBufBaseAddr + ); + if (EFI_ERROR (Status)) { + goto ErrorFreeAllocatedPages; + } + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &FlashInstance->Handle, + &gEfiDevicePathProtocol= Guid, + &FlashInstance->DeviceP= ath, + &gEfiFirmwareVolumeBloc= kProtocolGuid, + &FlashInstance->FvbProt= ocol, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorFreeAllocatedPages; + } + + Status =3D FvbPrepareFvHeader (FlashInstance); + if (EFI_ERROR (Status)) { + goto ErrorPrepareFvbHeader; + } + + return EFI_SUCCESS; + +ErrorPrepareFvbHeader: + gBS->UninstallMultipleProtocolInterfaces ( + &FlashInstance->Handle, + &gEfiDevicePathProtocolGuid, + &gEfiFirmwareVolumeBlockProtoc= olGuid, + 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 =3D AllocateRuntimeCopyPool ( + sizeof (mFvbFlashInstanceTemplate)= , + &mFvbFlashInstanceTemplate + ); + if (mFvbDevice =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + /* Detect and configure flash device */ + Status =3D FvbConfigureFlashInstance (mFvbDevice); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Fail to configure Fvb SPI device\n", __fun= c__)); + goto ErrorConfigureFlash; + } + + /* The driver implementing the variable read service can now be dispatch= ed; + * the varstore headers are in place. + */ + Status =3D 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, + &gEfiFirmwareVolumeBlockProtoc= olGuid, + NULL + ); + +ErrorConfigureFlash: + FreePool (mFvbDevice); + + return Status; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/Fvb= Dxe.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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __FVB_DXE_H__ +#define __FVB_DXE_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lb= a) * (LbaSize))) + +#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r') +#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLAS= H_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/Fvb= Dxe.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 =3D 0x0001001A + BASE_NAME =3D FvbDxe + FILE_GUID =3D DB8BFC83-6DEA-4AD1-AD3D-FDC579430233 + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 0.1 + ENTRY_POINT =3D 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 --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- 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/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-