From: Leif Lindholm <leif.lindholm@linaro.org>
To: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: edk2-devel@lists.01.org, daniel.thompson@linaro.org,
masami.hiramatsu@linaro.org
Subject: Re: [PATCH edk2-platforms v2 13/23] Silicon/Socionext: add driver for SPI NOR flash
Date: Thu, 26 Oct 2017 22:19:39 +0100 [thread overview]
Message-ID: <20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net> (raw)
In-Reply-To: <20171025175947.22798-14-ard.biesheuvel@linaro.org>
On Wed, Oct 25, 2017 at 06:59:37PM +0100, Ard Biesheuvel wrote:
> From: Pipat Methavanitpong <methavanitpong.pipat@socionext.com>
>
> This imports the driver sources provided by Socionext for the FIP006
> SPI NOR flash device found on SynQuacer SoCs. It has been slightly
> tweaked to bring it up to date with the changes made on the EDK2 side
> since it was forked.
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Pipat Methavanitpong <methavanitpong.pipat@socionext.com>
>
> [various tweaks and bugfixes]
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Do we need Contributed-under twice?
I'm not sure that carries any legal significane anyway.
Sorry, I would love to trim the below, but there are minor comments
spread throughout.
> ---
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec | 31 +
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf | 79 ++
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h | 244 ++++
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c | 138 ++
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c | 1376 ++++++++++++++++++++
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h | 314 +++++
> Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c | 859 ++++++++++++
> 7 files changed, 3041 insertions(+)
>
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec
> new file mode 100644
> index 000000000000..aec95bc82387
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec
> @@ -0,0 +1,31 @@
> +## @file
> +# Socionext FIP006 High-Speed SPI Controller with NOR Flash Driver
> +#
> +# Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> +#
> +# This program and the accompanying materials
> +# are licensed and made available under the terms and conditions of the BSD License
> +# which accompanies this distribution. The full text of the license may be found at
> +# http://opensource.org/licenses/bsd-license.php
> +#
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x0001001A
> + PACKAGE_NAME = Fip006DxePkg
> + PACKAGE_GUID = ABC7870B-FE82-4DAD-8179-FEC5F5194FA0
> + PACKAGE_VERSION = 0.1
> +
> +[Guids]
> + gFip006DxeTokenSpaceGuid = {0x4D45399E, 0x98F9, 0x4127, {0x8F, 0xB9,0xF8, 0xDE, 0x22, 0xA1, 0x09, 0x2C}}
> +
> +[PcdsFixedAtBuild]
> + gFip006DxeTokenSpaceGuid.PcdFip006DxeRegBaseAddress|0x0|UINT32|0x00000001
> + gFip006DxeTokenSpaceGuid.PcdFip006DxeMemBaseAddress|0x0|UINT32|0x00000002
> + gFip006DxeTokenSpaceGuid.PcdN25qSlaveId|0x0|UINT8|0x00000003
> + gFip006DxeTokenSpaceGuid.PcdN25qBlockSize|256|UINT32|0x00000004
> + gFip006DxeTokenSpaceGuid.PcdN25qBlockCount|524288|UINT32|0x00000005
> +
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf
> new file mode 100644
> index 000000000000..145aeb442d90
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf
> @@ -0,0 +1,79 @@
> +## @file
> +# Socionext FIP006 High-Speed SPI Controller with NOR Flash Driver
> +#
> +# Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +#
> +# This program and the accompanying materials
> +# are licensed and made available under the terms and conditions of the BSD License
> +# which accompanies this distribution. The full text of the license may be found at
> +# http://opensource.org/licenses/bsd-license.php
> +#
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +##
> +
> +
> +[Defines]
> + INF_VERSION = 0x0001001A
> + BASE_NAME = Fip006Dxe
> + FILE_GUID = 44F7D21F-C36F-4766-BC5B-C72E97E6897B
> + MODULE_TYPE = DXE_RUNTIME_DRIVER
> + VERSION_STRING = 0.1
> + ENTRY_POINT = NorFlashInitialise
> +
> +[Sources]
> + NorFlashDxe.c
> + NorFlashBlockIoDxe.c
> + NorFlashFvbDxe.c
Sort?
> +
> +[Packages]
> + ArmPlatformPkg/ArmPlatformPkg.dec
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + DebugLib
> + DevicePathLib
> + DxeServicesTableLib
> + HobLib
> + IoLib
> + MemoryAllocationLib
> + NorFlashPlatformLib
> + UefiLib
Move down two rows?
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiRuntimeLib
> + UefiRuntimeServicesTableLib
> +
> +[Guids]
> + gEfiAuthenticatedVariableGuid
> + gEfiEventVirtualAddressChangeGuid
> + gEfiSystemNvDataFvGuid
> + gEfiVariableGuid
> +
> +[Protocols]
> + gEfiBlockIoProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEfiDiskIoProtocolGuid
> + gEfiFirmwareVolumeBlockProtocolGuid
> +
> +[FixedPcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> + gFip006DxeTokenSpaceGuid.PcdFip006DxeRegBaseAddress
> + gFip006DxeTokenSpaceGuid.PcdFip006DxeMemBaseAddress
> +
> +[Depex]
> + #
> + # NorFlashDxe must be loaded before VariableRuntimeDxe in case empty flash needs populating with default values
> + #
> + BEFORE gVariableRuntimeDxeFileGuid
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h
> new file mode 100644
> index 000000000000..3d758dc492f6
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h
> @@ -0,0 +1,244 @@
> +/** @file
> + Socionext FIP006 Register List
> +
> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD License
> + which accompanies this distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __EFI_FIP006_REG_H__
> +#define __EFI_FIP006_REG_H__
> +
> +#define FIP006_REG_MCTRL 0x00 // Module Control
> +typedef union {
> + UINT32 Raw : 32;
> + struct {
> + BOOLEAN MEN : 1;
> + BOOLEAN CSEN : 1;
> +#define MCTRL_CSEN_DIRECT 0
> +#define MCTRL_CSEN_CS 1
> + BOOLEAN CDSS : 1;
> +#define MCTRL_CDSS_IHCLK 0
> +#define MCTRL_CDSS_IPCLK 1
> + BOOLEAN MES : 1;
> +#define MCTRL_MES_READY 1
> + UINT8 : 4;
> + UINT8 : 8;
> + UINT8 : 8;
> + UINT8 : 8;
> + };
> +} FIP006_MCTRL;
> +
> +#define FIP006_REG_PCC0 0x04 // Peripheral Communication Control 0
> +#define FIP006_REG_PCC1 0x08 // Peripheral Communication Control 1
> +#define FIP006_REG_PCC2 0x0C // Peripheral Communication Control 2
> +#define FIP006_REG_PCC3 0x10 // Peripheral Communication Control 3
> +typedef union {
> + UINT32 Raw : 32;
> + struct {
> + BOOLEAN CPHA : 1;
> + BOOLEAN CPOL : 1;
> + BOOLEAN ACES : 1;
> + BOOLEAN RTM : 1;
> + BOOLEAN SSPOL : 1;
> + UINT8 SS2CD : 2;
> + BOOLEAN SDIR : 1;
> +#define PCC_SDIR_MS_BIT 0
> +#define PCC_SDIR_LS_BIT 1
> + BOOLEAN SENDIAN : 1;
> +#define PCC_SENDIAN_BIG 0
> +#define PCC_SENDIAN_LITTLE 1
> + UINT8 CDRS : 7;
> + BOOLEAN SAFESYNC : 1;
> + UINT8 WRDSEL : 4;
> + UINT8 RDDSEL : 2;
> + UINT8 : 1;
> + UINT8 : 8;
> + } Reg;
> +} FIP006_PCC;
> +typedef FIP006_PCC FIP006_PCC0, FIP006_PCC1, FIP006_PCC2, FIP006_PCC3;
> +
> +#define FIP006_REG_TXF 0x14 // Tx Interrupt Flag
> +#define TXF_TSSRS BIT6
> +#define TXF_TFMTS BIT5
> +#define TXF_TFLETS BIT4
> +#define TXF_TFUS BIT3
> +#define TXF_TFOS BIT2
> +#define TXF_TFES BIT1
> +#define TXF_TFFS BIT0
> +
> +#define FIP006_REG_TXE 0x18 // Tx Interrupt Enable
> +#define TXE_TSSRE BIT6
> +#define TXE_TFMTE BIT5
> +#define TXE_TFLETE BIT4
> +#define TXE_TFUE BIT3
> +#define TXE_TFOE BIT2
> +#define TXE_TFEE BIT1
> +#define TXE_TFFE BIT0
> +
> +#define FIP006_REG_TXC 0x1C // Tx Interrupt Clear
> +#define TXC_TSSRC BIT6
> +#define TXC_TFMTC BIT5
> +#define TXC_TFLETC BIT4
> +#define TXC_TFUC BIT3
> +#define TXC_TFOC BIT2
> +#define TXC_TFEC BIT1
> +#define TXC_TFFC BIT0
> +
> +#define FIP006_REG_RXF 0x20 // Rx Interrupt Flag
> +#define RXF_RSSRS BIT6
> +#define RXF_RFMTS BIT5
> +#define RXF_RFLETS BIT4
> +#define RXF_RFUS BIT3
> +#define RXF_RFOS BIT2
> +#define RXF_RFES BIT1
> +#define RXF_RFFS BIT0
> +
> +#define FIP006_REG_RXE 0x24 // Rx Interrupt Enable
> +#define RXE_RSSRE BIT6
> +#define RXE_RFMTE BIT5
> +#define RXE_RFLETE BIT4
> +#define RXE_RFUE BIT3
> +#define RXE_RFOE BIT2
> +#define RXE_RFEE BIT1
> +#define RXE_RFFE BIT0
> +
> +#define FIP006_REG_RXC 0x28 // Rx Interrupt Clear
> +#define RXC_RSSRC BIT6
> +#define RXC_RFMTC BIT5
> +#define RXC_RFLETC BIT4
> +#define RXC_RFUC BIT3
> +#define RXC_RFOC BIT2
> +#define RXC_RFEC BIT1
> +#define RXC_RFFC BIT0
> +
> +#define FIP006_REG_FAULTF 0x2C // Error Interrupt Status
> +#define FAULTF_DRCBSFS BIT4
> +#define FAULTF_DWCBSFS BIT3
> +#define FAULTF_PVFS BIT2
> +#define FAULTF_WAFS BIT1
> +#define FAULTF_UMAFS BIT0
> +
> +#define FIP006_REG_FAULTC 0x30 // Error Interrupt Clear
> +#define FAULTC_DRCBSFC BIT4
> +#define FAULTC_DWCBSFC BIT3
> +#define FAULTC_PVFC BIT2
> +#define FAULTC_WAFC BIT1
> +#define FAULTC_UMAFC BIT0
> +
> +#define FIP006_REG_DM_CFG 0x34 // Direct Mode DMA Configuration
> +#define DM_CFG_MSTARTEN BIT2
> +#define DM_CFG_SSDC BIT1
> +
> +#define FIP006_REG_DM_DMA 0x35 // Direct Mode DMA Enable
> +#define DM_DMA_TXDMAEN BIT1
> +#define DM_DMA_RXDMAEN BIT0
> +
> +#define FIP006_REG_DM_START 0x38 // Direct Mode Start Transmission
> +#define DM_START BIT0
> +#define FIP006_REG_DM_STOP 0x39 // Direct Mode Stop Transmission
> +#define DM_STOP BIT0
> +
> +#define FIP006_REG_DM_PSEL 0x3A // Direct Mode Peripheral Select
> +#define DM_PSEL (BIT1 | BIT0)
> +
> +#define FIP006_REG_DM_TRP 0x3B // Direct Mode Transmission Protocol
> +#define DM_TRP (BIT3 | BIT2 | BIT1 | BIT0)
> +
> +#define FIP006_REG_DM_BCC 0x3C // Direct Mode Byte Count Control
> +#define FIP006_REG_DM_BCS 0x3E // Direct Mode Byte Count Status
> +
> +#define FIP006_REG_DM_STATUS 0x40 // Direct Mode Status
> +#define DM_STATUS_TXFLEVEL (BIT20 | BIT19 | BIT18 | BIT17 | BIT16)
> +#define DM_STATUS_RXFLEVEL (BIT20 | BIT19 | BIT18 | BIT17 | BIT16)
> +#define DM_STATUS_TXACTIVE BIT1
> +#define DM_STATUS_RXACTIVE BIT0
> +
> +#define FIP006_REG_FIFO_CFG 0x4C // FIFO Configuration
> +#define FIFO_CFG_TXFLSH BIT12
> +#define FIFO_CFG_RXFLSH BIT11
> +#define FIFO_CFG_TXCTRL BIT10
> +#define FIFO_CFG_FWIDTH (BIT9 | BIT8)
> +#define FIFO_CFG_TXFTH (BIT7 | BIT6 | BIT5 | BIT4)
> +#define FIFO_CFG_RXFTH (BIT3 | BIT2 | BIT1 | BIT0)
> +
> +#define FIP006_REG_FIFO_TX 0x50 // 16 32-bit Tx FIFO
> +#define FIP006_REG_FIFO_RX 0x90 // 16 32-bit Rx FIFO
> +
> +#define FIP006_REG_CS_CFG 0xD0 // Command Sequencer Configuration
> +typedef union {
> + UINT32 Raw : 32;
> + struct {
> + BOOLEAN SRAM : 1;
> +#define CS_CFG_SRAM_RO 0
> +#define CS_CFG_SRAM_RW 1
> + UINT8 MBM : 2;
> +#define CS_CFG_MBM_SINGLE 0
> +#define CS_CFG_MBM_DUAL 1
> +#define CS_CFG_MBM_QUAD 2
> + BOOLEAN SPICHNG : 1;
> + BOOLEAN BOOTEN : 1;
> + BOOLEAN BSEL : 1;
> + UINT8 : 2;
> + BOOLEAN SSEL0EN : 1;
> + BOOLEAN SSEL1EN : 1;
> + BOOLEAN SSEL2EN : 1;
> + BOOLEAN SSEL3EN : 1;
> + UINT8 : 4;
> + BOOLEAN MSEL : 4;
> + UINT8 : 4;
> + UINT8 : 8;
> + } Reg;
> +} FIP006_CS_CFG;
> +
> +#define FIP006_REG_CS_ITIME 0xD4 // Command Sequencer Idle Timer
> +typedef union {
> + UINT32 Raw : 32;
> + struct {
> + UINT16 ITIME : 16;
> + UINT16 : 16;
> + } Reg;
> +} FIP006_CS_ITIME;
> +#define FIP006_REG_CS_AEXT 0xD8 // Command Sequencer Address Extension
> +typedef union {
> + UINT32 Raw : 32;
> + struct {
> + UINT16 : 13;
> + UINT32 AEXT : 19;
> + } Reg;
> +} FIP006_CS_AEXT;
> +
> +#define FIP006_REG_CS_RD 0xDC // Command Sequencer Read Control
> +#define CS_RD_DEPTH 8
> +#define FIP006_REG_CS_WR 0xEC // Command Sequencer Write Control
> +#define CS_WR_DEPTH 8
> +typedef union {
> + UINT16 Raw : 16;
> + struct {
> + BOOLEAN DEC : 1;
> + UINT8 TRP : 2;
> + BOOLEAN CONT : 1;
> + UINT8 : 4;
> + union {
> + UINT8 Data : 8;
> + struct {
> + UINT8 Data : 3;
> + UINT8 : 5;
> + } Cmd;
> + } Payload;
> + } Reg;
> +} FIP006_CS_CMD;
> +typedef FIP006_CS_CMD FIP006_CS_RD, FIP006_CS_WR;
> +
> +#define FIP006_REG_MID 0xFC // Command Sequencer Module ID
> +typedef UINT32 FIP006_MID;
> +
> +#endif
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c
> new file mode 100644
> index 000000000000..b41f5003217c
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c
> @@ -0,0 +1,138 @@
> +/** @file NorFlashBlockIoDxe.c
> +
> + Copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD License
> + which accompanies this distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include "NorFlashDxe.h"
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoReset (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN BOOLEAN ExtendedVerification
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_BLKIO_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReset(MediaId=0x%x)\n",
> + This->Media->MediaId));
> +
> + return NorFlashReset (Instance);
> +}
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoReadBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> + EFI_STATUS Status;
> + EFI_BLOCK_IO_MEDIA *Media;
> +
> + if (This == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Instance = INSTANCE_FROM_BLKIO_THIS(This);
> + Media = This->Media;
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashBlockIoReadBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes "
> + "(%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));
> +
> + if (!Media) {
> + Status = EFI_INVALID_PARAMETER;
> + } else if (!Media->MediaPresent) {
> + Status = EFI_NO_MEDIA;
> + } else if (Media->MediaId != MediaId) {
> + Status = EFI_MEDIA_CHANGED;
> + } else if ((Media->IoAlign > 2) &&
> + (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
> + Status = EFI_INVALID_PARAMETER;
> + } else {
> + Status = NorFlashReadBlocks (Instance, Lba, BufferSizeInBytes, Buffer);
> + }
> +
> + return Status;
> +}
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoWriteBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + IN VOID *Buffer
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> + EFI_STATUS Status;
> +
> + Instance = INSTANCE_FROM_BLKIO_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashBlockIoWriteBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes "
> + "(%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));
> +
> + if( !This->Media->MediaPresent ) {
> + Status = EFI_NO_MEDIA;
> + } else if( This->Media->MediaId != MediaId ) {
> + Status = EFI_MEDIA_CHANGED;
> + } else if( This->Media->ReadOnly ) {
> + Status = EFI_WRITE_PROTECTED;
> + } else {
> + Status = NorFlashWriteBlocks (Instance,Lba,BufferSizeInBytes,Buffer);
> + }
> +
> + return Status;
> +}
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoFlushBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This
> + )
> +{
> + // No Flush required for the NOR Flash driver
> + // because cache operations are not permitted.
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashBlockIoFlushBlocks: Function NOT IMPLEMENTED (not required).\n"));
> +
> + // Nothing to do so just return without error
> + return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c
> new file mode 100644
> index 000000000000..d9cf11dd5be5
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c
> @@ -0,0 +1,1376 @@
> +/** @file NorFlashDxe.c
> +
> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +
> + This program and the accompanying materials are licensed and made available
> + under the terms and conditions of the BSD License which accompanies this
> + distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Library/UefiLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/PcdLib.h>
Move up one row?
> +
> +#include "NorFlashDxe.h"
> +
> +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
> +
> +//
> +// Global variable declarations
> +//
> +STATIC NOR_FLASH_INSTANCE **mNorFlashInstances;
> +STATIC UINT32 mNorFlashDeviceCount;
> +
> +STATIC CONST UINT16 mFip006NullCmdSeq[] = {
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1),
> + CSDC (0x07, 0, CSDC_TRP_MBM, 1)
Can we get some helpful #defines for these live-coded values please?
> +};
> +
> +STATIC CONST CSDC_DEFINITION mN25qCSDCDefTable[] = {
> + // Identification Operations
> + { 0x9F, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + // Register Operations
> + { 0x05, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0x01, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0xE8, TRUE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0x70, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0xB5, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0x85, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0x65, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + // Read Operations
> + { 0x13, TRUE, TRUE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + // Write Operations
> + { 0x02, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
> + { 0x32, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_QUAD, CSDC_TRP_SINGLE },
> + // Erase Operations
> + { 0xD8, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE },
Can we get some helpful #defines for these live-coded values please?
> +};
> +
> +STATIC
> +EFI_STATUS
> +NorFlashSetHostCSDC (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN BOOLEAN ReadWrite,
> + IN CONST UINT16 CSDC[8]
> + )
> +{
> + EFI_PHYSICAL_ADDRESS Dst;
> + UINTN Index;
> +
> + Dst = Instance->HostRegisterBaseAddress
> + + (ReadWrite ? FIP006_REG_CS_WR : FIP006_REG_CS_RD);
> + for (Index = 0; Index < 8; Index++) {
> + MmioWrite16 (Dst + (Index << 1), CSDC[Index]);
> + }
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +CONST CSDC_DEFINITION *
> +NorFlashGetCmdDef (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINT8 Code
> + )
> +{
> + CONST CSDC_DEFINITION *Cmd;
> + UINTN Index;
> +
> + Cmd = NULL;
> + for (Index = 0; Index < Instance->CmdTableSize; Index++) {
> + if (Code == Instance->CmdTable[Index].Code) {
> + Cmd = &Instance->CmdTable[Index];
> + break;
> + }
> + }
> + return Cmd;
> +}
> +
> +STATIC
> +EFI_STATUS
> +GenCSDC (
> + IN UINT8 Cmd,
> + IN BOOLEAN AddrAccess,
> + IN BOOLEAN AddrMode4Byte,
> + IN BOOLEAN HighZ,
> + IN UINT8 TransferMode,
> + OUT UINT16 CmdSeq[8]
> + )
> +{
> + UINTN Index;
> +
> + if (!CmdSeq) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Index = 0;
> + CopyMem (CmdSeq, mFip006NullCmdSeq, 8 * sizeof (UINT16));
> +
> + CmdSeq[Index++] = CSDC (Cmd, 0, TransferMode, 0);
> + if (AddrAccess) {
> + if (AddrMode4Byte) {
> + CmdSeq[Index++] = CSDC (0x03, 0, TransferMode, 1);
> + }
> + CmdSeq[Index++] = CSDC (0x02, 0, TransferMode, 1);
> + CmdSeq[Index++] = CSDC (0x01, 0, TransferMode, 1);
> + CmdSeq[Index++] = CSDC (0x00, 0, TransferMode, 1);
> + }
> + if (HighZ) {
> + CmdSeq[Index++] = CSDC (0x04, 0, TransferMode, 1);
Can we get some helpful #defines for these live-coded values please?
(That includes the 1s and 0s.
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashSetHostCommand (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINT8 Code
> + )
> +{
> + CONST CSDC_DEFINITION *Cmd;
> + UINT16 CSDC[8];
Feels like we should be able to have a #define for that 8 as well.
> +
> + Cmd = NorFlashGetCmdDef(Instance, Code);
> + if (Cmd == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + GenCSDC (
> + Cmd->Code,
> + Cmd->AddrAccess,
> + Cmd->AddrMode4Byte,
> + Cmd->HighZ,
> + Cmd->CsdcTrp,
> + CSDC
> + );
> + NorFlashSetHostCSDC (Instance, Cmd->ReadWrite, CSDC);
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +UINT8
> +NorFlashReadStatusRegister (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN SR_Address
> + )
> +{
> + UINT8 StatusRegister;
> +
> + NorFlashSetHostCommand (Instance, 0x05);
> + StatusRegister = NOR_FLASH_READ_BYTE (Instance, 0);
> + NorFlashSetHostCommand (Instance, 0x13);
Can we get some helpful #defines for these live-coded values please?
> + return StatusRegister;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashWaitProgramErase (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + BOOLEAN SRegDone;
> + BOOLEAN FSRegDone;
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashWaitProgramErase()\n"));
> +
> + do {
> + SRegDone = (NorFlashReadStatusRegister (Instance, 0) & BIT0) == 0;
> + FSRegDone = TRUE;
> + if (Instance->Flags & NOR_FLASH_POLL_FSR) {
> + NorFlashSetHostCommand (Instance, 0x70);
> + FSRegDone = (NOR_FLASH_READ_BYTE (Instance, 0) & BIT7) == BIT7;
> + }
> + } while (!SRegDone || !FSRegDone);
> + NorFlashSetHostCommand (Instance, 0x13);
Can we get some helpful #defines for these live-coded values please?
(BIT* is no more descriptive than 0x13.)
> + return EFI_SUCCESS;
> +}
> +
> +// TODO: implement lock checking
> +STATIC
> +BOOLEAN
> +NorFlashBlockIsLocked (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + )
> +{
> + return FALSE;
> +}
> +
> +// TODO: implement sector unlocking
> +STATIC
> +EFI_STATUS
> +NorFlashUnlockSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashUnlockSingleBlockIfNecessary (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) {
> + Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
> + }
> +
> + return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashEnableWrite (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 StatusRegister;
> + UINTN Retry;
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashEnableWrite()\n"));
> +
> + Status = EFI_DEVICE_ERROR;
> + Retry = 100;
Why 100 retries?
Use a delay instead?
Barrier?
> +
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> + while (Retry > 0 && EFI_ERROR (Status)) {
> + NOR_FLASH_WRITE_BYTE (Instance, 0, 0x06);
> + StatusRegister = NorFlashReadStatusRegister (Instance, 0);
> + Status = (StatusRegister & BIT1) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
Can we get some helpful #defines for these live-coded values please?
> + Retry--;
> + }
> + return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashDisableWrite (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 StatusRegister;
> + UINTN Retry;
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashDisableWrite()\n"));
> +
> + Status = EFI_DEVICE_ERROR;
> + Retry = 10;
10 retries is better than 100, but still quite arbitrary.
Delay?
Barrier?
> +
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> + while (Retry > 0 && EFI_ERROR (Status)) {
> + NOR_FLASH_WRITE_BYTE (Instance, 0, 0x04);
> + StatusRegister = NorFlashReadStatusRegister (Instance, 0);
> + Status = (StatusRegister & BIT1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
Can we get some helpful #defines for these live-coded values please?
> + Retry--;
> + }
> + return Status;
> +}
> +
> +/**
> + * The following function presumes that the block has already been unlocked.
> + **/
> +//
> +// TODO: Support 4-byte addressing erase block
> +//
> +// The current implementation supports only 3-byte addressing
> +// i.e. 64KB-block 0x00-0xFF can be erased.
> +// To make a 3-byte address fits in a memory access, the implementation
> +// merges the 1-byte erase cmd and a 3-byte address to form a 4-byte data.
> +//
> +// To support 4-byte addresing, it could be implemented by either
> +// 1. configuring to select bottom/top of a flash device
> +// 2. entering 4-byte addressing mode and send erase cmd via cmd sequence
> +// and a target 4-byte block address as data
> +//
> +// TODO: Handle endianess
> +//
> +// The current implementation assumes CPU is little-endian and
> +// FIP006 is set to transfer from big-endian
> +//
> +// For exmaple: Data = 0xAABBCCDD
> +//
> +// Addr offset 00 01 02 03
> +// Data DD CC BB AA
> +// Transfer Dir <----------
> +//
> +STATIC
> +EFI_STATUS
> +NorFlashEraseSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + )
> +{
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n", BlockAddress));
> +
> + if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + //
> + // The virtual address chosen by the OS may have a different offset modulo
> + // 16 MB than the physical address, so we need to subtract the region base
> + // address before we can mask off a block index. Note that the relative
> + // offset between device base address and region base address may have changed
> + // as well, so we cannot use the device base address directly.
> + //
> + if (EfiAtRuntime()) {
> + BlockAddress -= Instance->RegionBaseAddress;
> + BlockAddress += Instance->OffsetLba * Instance->Media.BlockSize;
> + }
> +
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> + ((UINT32*)Instance->DeviceBaseAddress)[0] = (SwapBytes32 (BlockAddress & 0x00FFFFFF)) | 0xD8;
This looks like a helper macro waiting to happen.
> + NorFlashWaitProgramErase (Instance);
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> +
> + if (EFI_ERROR (NorFlashDisableWrite (Instance))) {
> + return EFI_DEVICE_ERROR;
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + * This function unlock and erase an entire NOR Flash block.
> + **/
> +EFI_STATUS
> +NorFlashUnlockAndEraseSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Index;
> + EFI_TPL OriginalTPL;
> + BOOLEAN InterruptsEnabled;
> +
> + OriginalTPL = 0;
> + InterruptsEnabled = FALSE;
> +
> + if (!EfiAtRuntime ()) {
> + // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
> + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> + } else {
> + InterruptsEnabled = SaveAndDisableInterrupts ();
> + }
> +
> + Index = 0;
> + // The block erase might fail a first time (SW bug ?). Retry it ...
Not just missing barriers?
> + do {
> + // Unlock the block if we have to
> + Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> + Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
> + Index++;
> + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
> +
> + if (Index == NOR_FLASH_ERASE_RETRY) {
> + DEBUG ((DEBUG_ERROR,
> + "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n",
> + BlockAddress,Index));
> + }
> +
> + if (!EfiAtRuntime ()) {
> + // Interruptions can resume.
> + gBS->RestoreTPL (OriginalTPL);
> + } else if (InterruptsEnabled) {
> + SetInterruptState (TRUE);
> + }
> +
> + return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashWriteSingleWord (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN WordAddress,
> + IN UINT32 WriteData
> + )
> +{
> + EFI_STATUS Status;
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n",
> + WordAddress, WriteData));
> +
> + Status = EFI_SUCCESS;
> +
> + if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
> + return EFI_DEVICE_ERROR;
> + }
> + NorFlashSetHostCommand (Instance, 0x02);
Can we get a helpful #define for this live-coded value please?
> + MmioWrite32 (WordAddress, WriteData);
> + NorFlashWaitProgramErase (Instance);
> +
> + NorFlashDisableWrite (Instance);
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> + return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NorFlashWriteFullBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINT32 *DataBuffer,
> + IN UINT32 BlockSizeInWords
> + )
> +{
> + EFI_STATUS Status;
> + UINTN WordAddress;
> + UINT32 WordIndex;
> + UINTN BlockAddress;
> + EFI_TPL OriginalTPL;
> + BOOLEAN InterruptsEnabled;
> +
> + Status = EFI_SUCCESS;
> + OriginalTPL = 0;
> + InterruptsEnabled = FALSE;
> +
> + // Get the physical address of the block
> + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
> + BlockSizeInWords * 4);
> +
> + // Start writing from the first address at the start of the block
> + WordAddress = BlockAddress;
> +
> + if (!EfiAtRuntime ()) {
> + // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
> + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> + } else {
> + InterruptsEnabled = SaveAndDisableInterrupts ();
> + }
> +
> + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR,
> + "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
> + BlockAddress));
> + goto EXIT;
> + }
> +
> + for (WordIndex=0;
> + WordIndex < BlockSizeInWords;
> + WordIndex++, DataBuffer++, WordAddress += 4) {
> + Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
> + if (EFI_ERROR (Status)) {
> + goto EXIT;
> + }
> + }
> +
> +EXIT:
> + if (!EfiAtRuntime ()) {
> + // Interruptions can resume.
> + gBS->RestoreTPL (OriginalTPL);
> + } else if (InterruptsEnabled) {
> + SetInterruptState (TRUE);
> + }
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR,
> + "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n",
> + WordAddress, Status));
> + }
> + return Status;
> +}
> +
> +EFI_STATUS
> +NorFlashWriteBlocks (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + IN VOID *Buffer
> + )
> +{
> + UINT32 *pWriteBuffer;
> + EFI_STATUS Status = EFI_SUCCESS;
> + EFI_LBA CurrentBlock;
> + UINT32 BlockSizeInWords;
> + UINT32 NumBlocks;
> + UINT32 BlockCount;
> +
> + // The buffer must be valid
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if(Instance->Media.ReadOnly == TRUE) {
> + return EFI_WRITE_PROTECTED;
> + }
> +
> + // We must have some bytes to read
> + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n",
> + BufferSizeInBytes));
> + if(BufferSizeInBytes == 0) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // The size of the buffer must be a multiple of the block size
> + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n",
> + Instance->Media.BlockSize));
> + if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // All blocks must be within the device
> + NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks,
> + Instance->Media.LastBlock, Lba));
> +
> + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + BlockSizeInWords = Instance->Media.BlockSize / 4;
> +
> + // Because the target *Buffer is a pointer to VOID, we must put
> + // all the data into a pointer to a proper data type, so use *ReadBuffer
May be worth doing an ASSERT ((Buffer & 0x3) == 0) here.
or ASSERT ((Buffer & (sizeof (UINT32) - 1))) to be more explicit.
> + pWriteBuffer = (UINT32 *)Buffer;
> +
> + CurrentBlock = Lba;
> + for (BlockCount = 0;
> + BlockCount < NumBlocks;
> + BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) {
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n",
> + (UINTN)CurrentBlock));
> +
> + Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer,
> + BlockSizeInWords);
> +
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> + }
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
> + return Status;
> +}
> +
> +EFI_STATUS
> +NorFlashReadBlocks (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> + )
> +{
> + UINT32 NumBlocks;
> + UINTN StartAddress;
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
> + BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock,
> + Lba));
> +
> + // The buffer must be valid
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Return if we have not any byte to read
> + if (BufferSizeInBytes == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + // The size of the buffer must be a multiple of the block size
> + if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // All blocks must be within the device
> + NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
> +
> + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Get the address to start reading from
> + StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
> + Instance->Media.BlockSize);
> +
> + // Put the device into Read Array mode
> + NorFlashSetHostCommand (Instance, 0x13);
Can we get a helpful #define for this live-coded value please?
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> +
> + // Readout the data
> + CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +NorFlashRead (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> + )
> +{
> + UINTN StartAddress;
> +
> + // The buffer must be valid
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Return if we have not any byte to read
> + if (BufferSizeInBytes == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) >
> + Instance->Size) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashRead: ERROR - Read will exceed device size.\n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Get the address to start reading from
> + StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
> + Instance->Media.BlockSize);
> +
> + // Put the device into Read Array mode
> + NorFlashSetHostCommand (Instance, 0x13);
Same value, so reuse the same #define?
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> +
> + // Readout the data
> + CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
> +
> + return EFI_SUCCESS;
> +}
The above two functions look nearly identical.
Could one be made to call the other with different parameters, or
could the be merged into one with an operation type flag?
> +
> +/*
> + Write a full or portion of a block. It must not span block boundaries;
> + that is, Offset + *NumBytes <= Instance->Media.BlockSize.
> +*/
> +EFI_STATUS
> +NorFlashWriteSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN OUT UINTN *NumBytes,
> + IN UINT8 *Buffer
> + )
> +{
> + EFI_STATUS TempStatus;
> + UINT32 Tmp;
> + UINT32 TmpBuf;
> + UINT32 WordToWrite;
> + UINT32 Mask;
> + BOOLEAN DoErase;
> + UINTN BytesToWrite;
> + UINTN CurOffset;
> + UINTN WordAddr;
> + UINTN BlockSize;
> + UINTN BlockAddress;
> + UINTN PrevBlockAddress;
> +
> + PrevBlockAddress = 0;
> +
> + if (!Instance->Initialized && Instance->Initialize) {
> + Instance->Initialize(Instance);
> + }
> +
> + DEBUG ((DEBUG_BLKIO,
> + "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
> + Lba, Offset, *NumBytes, Buffer));
> +
> + // Detect WriteDisabled state
> + if (Instance->Media.ReadOnly == TRUE) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
> + // It is in WriteDisabled state, return an error right away
> + return EFI_ACCESS_DENIED;
> + }
> +
> + // Cache the block size to avoid de-referencing pointers all the time
> + BlockSize = Instance->Media.BlockSize;
> +
> + // The write must not span block boundaries.
> + // We need to check each variable individually because adding two large
> + // values together overflows.
> + if (Offset >= BlockSize ||
> + *NumBytes > BlockSize ||
> + (Offset + *NumBytes) > BlockSize) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
> + Offset, *NumBytes, BlockSize ));
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // We must have some bytes to write
> + if (*NumBytes == 0) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
> + Offset, *NumBytes, BlockSize ));
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // Pick 128bytes as a good start for word operations as opposed to erasing the
> + // block and writing the data regardless if an erase is really needed.
> + // It looks like most individual NV variable writes are smaller than 128bytes.
> + if (*NumBytes <= 128) {
> + // Check to see if we need to erase before programming the data into NOR.
> + // If the destination bits are only changing from 1s to 0s we can just write.
> + // After a block is erased all bits in the block is set to 1.
> + // If any byte requires us to erase we just give up and rewrite all of it.
> + DoErase = FALSE;
> + BytesToWrite = *NumBytes;
> + CurOffset = Offset;
> +
> + while (BytesToWrite > 0) {
> + // Read full word from NOR, splice as required. A word is the smallest
> + // unit we can write.
> + TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp),
> + &Tmp);
> + if (EFI_ERROR (TempStatus)) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + // Physical address of word in NOR to write.
> + WordAddr = (CurOffset & ~(0x3)) +
> + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
> + BlockSize);
> +
> + // The word of data that is to be written.
> + TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite)));
> +
> + // First do word aligned chunks.
> + if ((CurOffset & 0x3) == 0) {
> + if (BytesToWrite >= 4) {
> + // Is the destination still in 'erased' state?
> + if (~Tmp != 0) {
> + // Check to see if we are only changing bits to zero.
> + if ((Tmp ^ TmpBuf) & TmpBuf) {
> + DoErase = TRUE;
> + break;
> + }
> + }
> + // Write this word to NOR
> + WordToWrite = TmpBuf;
> + CurOffset += sizeof(TmpBuf);
> + BytesToWrite -= sizeof(TmpBuf);
> + } else {
> + // BytesToWrite < 4. Do small writes and left-overs
> + Mask = ~((~0) << (BytesToWrite * 8));
> + // Mask out the bytes we want.
> + TmpBuf &= Mask;
> + // Is the destination still in 'erased' state?
> + if ((Tmp & Mask) != Mask) {
> + // Check to see if we are only changing bits to zero.
> + if ((Tmp ^ TmpBuf) & TmpBuf) {
> + DoErase = TRUE;
> + break;
> + }
> + }
> + // Merge old and new data. Write merged word to NOR
> + WordToWrite = (Tmp & ~Mask) | TmpBuf;
> + CurOffset += BytesToWrite;
> + BytesToWrite = 0;
> + }
> + } else {
> + // Do multiple words, but starting unaligned.
> + if (BytesToWrite > (4 - (CurOffset & 0x3))) {
> + Mask = ((~0) << ((CurOffset & 0x3) * 8));
> + // Mask out the bytes we want.
> + TmpBuf &= Mask;
> + // Is the destination still in 'erased' state?
> + if ((Tmp & Mask) != Mask) {
> + // Check to see if we are only changing bits to zero.
> + if ((Tmp ^ TmpBuf) & TmpBuf) {
> + DoErase = TRUE;
> + break;
> + }
> + }
> + // Merge old and new data. Write merged word to NOR
> + WordToWrite = (Tmp & ~Mask) | TmpBuf;
> + BytesToWrite -= (4 - (CurOffset & 0x3));
> + CurOffset += (4 - (CurOffset & 0x3));
> + } else {
> + // Unaligned and fits in one word.
> + Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
> + // Mask out the bytes we want.
> + TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
> + // Is the destination still in 'erased' state?
> + if ((Tmp & Mask) != Mask) {
> + // Check to see if we are only changing bits to zero.
> + if ((Tmp ^ TmpBuf) & TmpBuf) {
> + DoErase = TRUE;
> + break;
> + }
> + }
> + // Merge old and new data. Write merged word to NOR
> + WordToWrite = (Tmp & ~Mask) | TmpBuf;
> + CurOffset += BytesToWrite;
> + BytesToWrite = 0;
> + }
> + }
> +
> + //
> + // Write the word to NOR.
> + //
> +
> + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
> + BlockSize);
> + if (BlockAddress != PrevBlockAddress) {
> + TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance,
> + BlockAddress);
> + if (EFI_ERROR (TempStatus)) {
> + return EFI_DEVICE_ERROR;
> + }
> + PrevBlockAddress = BlockAddress;
> + }
> + TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
> + if (EFI_ERROR (TempStatus)) {
> + return EFI_DEVICE_ERROR;
> + }
> + }
> + // Exit if we got here and could write all the data. Otherwise do the
> + // Erase-Write cycle.
> + if (!DoErase) {
> + return EFI_SUCCESS;
> + }
> + }
> +
> + // Check we did get some memory. Buffer is BlockSize.
> + if (Instance->ShadowBuffer == NULL) {
> + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + // Read NOR Flash data into shadow buffer
> + TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize,
> + Instance->ShadowBuffer);
> + if (EFI_ERROR (TempStatus)) {
> + // Return one of the pre-approved error statuses
> + return EFI_DEVICE_ERROR;
> + }
> +
> + // Put the data at the appropriate location inside the buffer area
> + CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
> +
> + // Write the modified buffer back to the NorFlash
> + TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize,
> + Instance->ShadowBuffer);
> + if (EFI_ERROR (TempStatus)) {
> + // Return one of the pre-approved error statuses
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
The above is waaay too long.
Can it be broken down with the help of some helper functions please?
> +
> +/*
> + Although DiskIoDxe will automatically install the DiskIO protocol whenever
> + we install the BlockIO protocol, its implementation is sub-optimal as it reads
> + and writes entire blocks using the BlockIO protocol. In fact we can access
> + NOR flash with a finer granularity than that, so we can improve performance
> + by directly producing the DiskIO protocol.
> +*/
> +
> +/**
> + Read BufferSize bytes from Offset into Buffer.
> +
> + @param This Protocol instance pointer.
> + @param MediaId Id of the media, changes every time the media is
> + replaced.
> + @param Offset The starting byte offset to read from
> + @param BufferSize Size of Buffer
> + @param Buffer Buffer containing read data
> +
> + @retval EFI_SUCCESS The data was read correctly from the device.
> + @retval EFI_DEVICE_ERROR The device reported an error while performing
> + the read.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
> + @retval EFI_INVALID_PARAMETER The read request contains device addresses that
> + are not valid for the device.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +NorFlashDiskIoReadDisk (
> + IN EFI_DISK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN UINT64 DiskOffset,
> + IN UINTN BufferSize,
> + OUT VOID *Buffer
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> + UINT32 BlockSize;
> + UINT32 BlockOffset;
> + EFI_LBA Lba;
> +
> + Instance = INSTANCE_FROM_DISKIO_THIS(This);
> +
> + if (MediaId != Instance->Media.MediaId) {
> + return EFI_MEDIA_CHANGED;
> + }
> +
> + BlockSize = Instance->Media.BlockSize;
> + Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
> +
> + return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
> +}
> +
> +/**
> + Writes a specified number of bytes to a device.
> +
> + @param This Indicates a pointer to the calling context.
> + @param MediaId ID of the medium to be written.
> + @param Offset The starting byte offset on the logical block I/O device to
> + write.
> + @param BufferSize The size in bytes of Buffer. The number of bytes to write
> + to the device.
> + @param Buffer A pointer to the buffer containing the data to be written.
> +
> + @retval EFI_SUCCESS The data was written correctly to the device.
> + @retval EFI_WRITE_PROTECTED The device can not be written to.
> + @retval EFI_DEVICE_ERROR The device reported an error while performing
> + the write.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
> + @retval EFI_INVALID_PARAMETER The write request contains device addresses that
> + are not valid for the device.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +NorFlashDiskIoWriteDisk (
> + IN EFI_DISK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN UINT64 DiskOffset,
> + IN UINTN BufferSize,
> + IN VOID *Buffer
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> + UINT32 BlockSize;
> + UINT32 BlockOffset;
> + EFI_LBA Lba;
> + UINTN RemainingBytes;
> + UINTN WriteSize;
> + EFI_STATUS Status;
> +
> + Instance = INSTANCE_FROM_DISKIO_THIS(This);
> +
> + if (MediaId != Instance->Media.MediaId) {
> + return EFI_MEDIA_CHANGED;
> + }
> +
> + BlockSize = Instance->Media.BlockSize;
> + Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
> +
> + RemainingBytes = BufferSize;
> +
> + // Write either all the remaining bytes, or the number of bytes that bring
> + // us up to a block boundary, whichever is less.
> + // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
> + // block boundary (even if it is already on one).
> + WriteSize = MIN (RemainingBytes,
> + ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);
> +
> + do {
> + if (WriteSize == BlockSize) {
> + // Write a full block
> + Status = NorFlashWriteFullBlock (Instance, Lba, Buffer,
> + BlockSize / sizeof (UINT32));
> + } else {
> + // Write a partial block
> + Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize,
> + Buffer);
> + }
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + // Now continue writing either all the remaining bytes or single blocks.
> + RemainingBytes -= WriteSize;
> + Buffer = (UINT8 *) Buffer + WriteSize;
> + Lba++;
> + BlockOffset = 0;
> + WriteSize = MIN (RemainingBytes, BlockSize);
> + } while (RemainingBytes);
> +
> + return Status;
> +}
> +
> +STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
> + NOR_FLASH_SIGNATURE, // Signature
> + NULL, // Handle ... NEED TO BE FILLED
By what?
> +
> + FALSE, // Initialized
> + NULL, // Initialize
> +
> + 0, // HostRegisterBaseAddress ... NEED TO BE FILLED
> + 0, // DeviceBaseAddress ... NEED TO BE FILLED
> + 0, // RegionBaseAddress ... NEED TO BE FILLED
> + 0, // Size ... NEED TO BE FILLED
> + 0, // StartLba
> + 0, // OffsetLba
> +
> + {
> + EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
> + NULL, // Media ... NEED TO BE FILLED
> + NorFlashBlockIoReset, // Reset;
> + NorFlashBlockIoReadBlocks, // ReadBlocks
> + NorFlashBlockIoWriteBlocks, // WriteBlocks
> + NorFlashBlockIoFlushBlocks // FlushBlocks
> + }, // BlockIoProtocol
> +
> + {
> + 0, // MediaId ... NEED TO BE FILLED
> + FALSE, // RemovableMedia
> + TRUE, // MediaPresent
> + FALSE, // LogicalPartition
> + FALSE, // ReadOnly
> + FALSE, // WriteCaching;
> + 0, // BlockSize ... NEED TO BE FILLED
> + 4, // IoAlign
> + 0, // LastBlock ... NEED TO BE FILLED
> + 0, // LowestAlignedLba
> + 1, // LogicalBlocksPerPhysicalBlock
> + }, //Media;
> +
> + {
> + EFI_DISK_IO_PROTOCOL_REVISION, // Revision
> + NorFlashDiskIoReadDisk, // ReadDisk
> + NorFlashDiskIoWriteDisk // WriteDisk
> + },
> + {
> + FvbGetAttributes, // GetAttributes
> + FvbSetAttributes, // SetAttributes
> + FvbGetPhysicalAddress, // GetPhysicalAddress
> + FvbGetBlockSize, // GetBlockSize
> + FvbRead, // Read
> + FvbWrite, // Write
> + FvbEraseBlocks, // EraseBlocks
> + NULL, //ParentHandle
> + }, // FvbProtoccol;
> +
> + NULL, // ShadowBuffer
> + {
> + {
> + {
> + HARDWARE_DEVICE_PATH,
> + HW_VENDOR_DP,
> + {
> + (UINT8)sizeof(VENDOR_DEVICE_PATH),
> + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)
> + }
> + },
> + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } },
> + },
> + {
> + END_DEVICE_PATH_TYPE,
> + END_ENTIRE_DEVICE_PATH_SUBTYPE,
> + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
> + }
> + }, // DevicePath
> +
> + NULL, // CmdTable
> + 0, // CmdTableSize
> + 0 // Flags
> +};
> +
> +STATIC
> +EFI_STATUS
> +NorFlashCreateInstance (
> + IN UINTN HostRegisterBase,
> + IN UINTN NorFlashDeviceBase,
> + IN UINTN NorFlashRegionBase,
> + IN UINTN NorFlashSize,
> + IN UINT32 MediaId,
> + IN UINT32 BlockSize,
> + IN BOOLEAN HasVarStore,
> + IN CONST GUID *NorFlashGuid,
> + IN CONST CSDC_DEFINITION *CommandTable,
> + IN UINTN CommandTableSize,
> + OUT NOR_FLASH_INSTANCE** NorFlashInstance
> + )
> +{
> + EFI_STATUS Status;
> + NOR_FLASH_INSTANCE* Instance;
> + UINT8 JedecId[3];
> +
> + ASSERT(NorFlashInstance != NULL);
> +
> + Instance = AllocateRuntimeCopyPool (sizeof mNorFlashInstanceTemplate,
> + &mNorFlashInstanceTemplate);
> + if (Instance == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Instance->HostRegisterBaseAddress = HostRegisterBase;
> + Instance->DeviceBaseAddress = NorFlashDeviceBase;
> + Instance->RegionBaseAddress = NorFlashRegionBase;
> + Instance->Size = NorFlashSize;
> +
> + Instance->BlockIoProtocol.Media = &Instance->Media;
> + Instance->Media.MediaId = MediaId;
> + Instance->Media.BlockSize = BlockSize;
> + Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
- 1;
> + Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize;
> +
> + CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid);
> +
> + Instance->CmdTable = CommandTable;
> + Instance->CmdTableSize = CommandTableSize;
> + NorFlashReset (Instance);
> +
> + NorFlashReadID (Instance, JedecId);
> + // Micron N25Q
> + if (JedecId[0] == 0x20 && (JedecId[1] == 0xBB || JedecId[1] == 0xBA)) {
> + Instance->Flags = NOR_FLASH_POLL_FSR;
> + }
> + // Macronix MX66U
> + else if (JedecId[0] == 0xC2 && JedecId[1] == 0x25) {
Can we get some helpful #defines for these live-coded values please?
> + Instance->Flags = 0;
> + }
> + else {
> + Instance->Flags = 0;
> + }
> +
> + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);;
> + if (Instance->ShadowBuffer == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + if (HasVarStore) {
> + Instance->Initialize = NorFlashFvbInitialize;
> + }
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &Instance->Handle,
> + &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
> + &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + FreePool (Instance);
> + return Status;
> + }
> +
> + *NorFlashInstance = Instance;
> + return Status;
> +}
> +
> +EFI_STATUS
> +NorFlashReset (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + FIP006_CS_CFG CsCfg;
> +
> + DEBUG ((DEBUG_BLKIO, "NorFlashReset()\n"));
> + NOR_FLASH_GET_HOST_REG(Instance, CS_CFG, CsCfg);
> + CsCfg.Reg.MBM = CS_CFG_MBM_SINGLE;
> + CsCfg.Reg.SRAM = CS_CFG_SRAM_RW;
> + NOR_FLASH_SET_HOST_REG(Instance, CS_CFG, CsCfg);
> + NorFlashSetHostCommand (Instance, 0x13);
Same 0x13 again?
> + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq);
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +NorFlashReadID (
> + IN NOR_FLASH_INSTANCE *Instance,
> + OUT UINT8 JedecId[3]
> + )
> +{
> + if (Instance == NULL || JedecId == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + NorFlashSetHostCommand (Instance, 0x9F);
> + JedecId[0] = ((UINT8*)Instance->DeviceBaseAddress)[0]; // Manufacturer ID
> + JedecId[1] = ((UINT8*)Instance->DeviceBaseAddress)[1]; // Memory Type
> + JedecId[2] = ((UINT8*)Instance->DeviceBaseAddress)[2]; // Memory Capacity
> + NorFlashSetHostCommand (Instance, 0x13);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Fixup internal data so that EFI can be call in virtual mode.
> + Call the passed in Child Notify event and convert any pointers in
> + lib to virtual mode.
> +
> + @param[in] Event The Event that is being processed
> + @param[in] Context Event Context
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +NorFlashVirtualNotifyEvent (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + UINTN Index;
> +
> + for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->HostRegisterBaseAddress);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);
> +
> + // Convert BlockIo protocol
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);
> +
> + // Convert Fvb
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
> + EfiConvertPointer (0x0,
> + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);
> +
> + if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
> + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer);
> + }
> +
> + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->CmdTable);
> + }
> +
> + return;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +NorFlashInitialise (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PHYSICAL_ADDRESS HostRegisterBaseAddress;
> + UINT32 Index;
> + NOR_FLASH_DESCRIPTION* NorFlashDevices;
> + BOOLEAN ContainVariableStorage;
> +
> + // Register HSSPI FIP006 register region
> + HostRegisterBaseAddress = PcdGet32 (PcdFip006DxeRegBaseAddress);
> +
> + Status = gDS->AddMemorySpace (
> + EfiGcdMemoryTypeMemoryMappedIo,
> + HostRegisterBaseAddress, SIZE_4KB,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gDS->SetMemorySpaceAttributes (
> + HostRegisterBaseAddress, SIZE_4KB,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = NorFlashPlatformInitialization ();
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
> + return Status;
> + }
> +
> + // Initialize NOR flash instances
> + Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
> + return Status;
> + }
> +
> + mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) *
> + mNorFlashDeviceCount);
> +
> + for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
> + // Check if this NOR Flash device contain the variable storage region
> + ContainVariableStorage =
> + (NorFlashDevices[Index].RegionBaseAddress <=
> + PcdGet32 (PcdFlashNvStorageVariableBase)) &&
> + (PcdGet32 (PcdFlashNvStorageVariableBase) +
> + PcdGet32 (PcdFlashNvStorageVariableSize) <=
> + NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
> +
> + Status = NorFlashCreateInstance (
> + HostRegisterBaseAddress,
> + NorFlashDevices[Index].DeviceBaseAddress,
> + NorFlashDevices[Index].RegionBaseAddress,
> + NorFlashDevices[Index].Size,
> + Index,
> + NorFlashDevices[Index].BlockSize,
> + ContainVariableStorage,
> + &NorFlashDevices[Index].Guid,
> + mN25qCSDCDefTable,
> + ARRAY_SIZE (mN25qCSDCDefTable),
> + &mNorFlashInstances[Index]
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR,
> + "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",
> + Index));
> + }
> + }
> +
> + //
> + // Register for the virtual address change event
> + //
> + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
> + NorFlashVirtualNotifyEvent, NULL,
> + &gEfiEventVirtualAddressChangeGuid,
> + &mNorFlashVirtualAddrChangeEvent);
> + ASSERT_EFI_ERROR (Status);
> +
> + return Status;
> +}
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h
> new file mode 100644
> index 000000000000..d5185dba3c63
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h
> @@ -0,0 +1,314 @@
> +/** @file NorFlashDxe.h
> +
> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +
> + This program and the accompanying materials
> + are licensed and made available under the terms and conditions of the BSD License
> + which accompanies this distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __NOR_FLASH_DXE_H__
> +#define __NOR_FLASH_DXE_H__
> +
> +
> +#include <Base.h>
> +#include <PiDxe.h>
> +
> +#include <Guid/EventGroup.h>
> +
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DiskIo.h>
> +#include <Protocol/FirmwareVolumeBlock.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/NorFlashPlatformLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeLib.h>
> +#include <Library/DxeServicesTableLib.h>
Sorted, please.
> +
> +#include "Fip006Reg.h"
> +
> +#define NOR_FLASH_ERASE_RETRY 10
I'm sure I saw a 10 retry count up there somewhere that did not use
this #define. It probably should.
> +
> +#define GET_NOR_BLOCK_ADDRESS(BaseAddr,Lba,LbaSize)( BaseAddr + (UINTN)((Lba) * LbaSize) )
> +
> +#define NOR_FLASH_READ_BYTE(Instance, Addr) \
> + (((UINT8*) Instance->RegionBaseAddress + Addr)[0])
> +
> +#define NOR_FLASH_WRITE_BYTE(Instance, Addr, Src) \
> + do { \
> + ((UINT8*) Instance->RegionBaseAddress + Addr)[0] = Src; \
> + } while (0)
> +
Umm, if not using MmioWrite8 (hint, it probably should), this pointer
should also flag volatile. x2.
> +#define NOR_FLASH_GET_HOST_REG(Instance, Reg, Dst) \
> + do { \
> + Dst.Raw = MmioRead32(Instance->HostRegisterBaseAddress + FIP006_REG_##Reg); \
> + } while (0)
> +
> +#define NOR_FLASH_SET_HOST_REG(Instance, Reg, Src) \
> + do { \
> + MmioWrite32 (Instance->HostRegisterBaseAddress + FIP006_REG_##Reg, Src.Raw); \
> + } while (0)
> +
> +#define NOR_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')
> +#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol, NOR_FLASH_SIGNATURE)
> +#define INSTANCE_FROM_BLKIO_THIS(a) CR(a, NOR_FLASH_INSTANCE, BlockIoProtocol, NOR_FLASH_SIGNATURE)
> +#define INSTANCE_FROM_DISKIO_THIS(a) CR(a, NOR_FLASH_INSTANCE, DiskIoProtocol, NOR_FLASH_SIGNATURE)
> +
> +#define CSDC(Data, Cont, Trp, Dec) \
> + ((Data << 8) | (Cont << 3) | (Trp << 1) | Dec)
Do these need some masking as well, for sanitisation?
> +#define CSDC_TRP_MBM 0
> +#define CSDC_TRP_DUAL 1
> +#define CSDC_TRP_QUAD 2
> +#define CSDC_TRP_SINGLE 3
> +
> +typedef struct {
> + UINT8 Code;
> + BOOLEAN AddrAccess;
> + BOOLEAN AddrMode4Byte;
> + BOOLEAN HighZ;
> + BOOLEAN ReadWrite;
> + UINT8 CscfgMbm;
> + UINT8 CsdcTrp;
> +} CSDC_DEFINITION;
> +
> +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
> +
> +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (NOR_FLASH_INSTANCE* Instance);
> +
> +typedef struct {
> + VENDOR_DEVICE_PATH Vendor;
> + EFI_DEVICE_PATH_PROTOCOL End;
> +} NOR_FLASH_DEVICE_PATH;
> +
> +struct _NOR_FLASH_INSTANCE {
> + UINT32 Signature;
> + EFI_HANDLE Handle;
> +
> + BOOLEAN Initialized;
> + NOR_FLASH_INITIALIZE Initialize;
> +
> + UINTN HostRegisterBaseAddress;
> + UINTN DeviceBaseAddress;
> + UINTN RegionBaseAddress;
> + UINTN Size;
> + EFI_LBA StartLba;
> + EFI_LBA OffsetLba;
> +
> + EFI_BLOCK_IO_PROTOCOL BlockIoProtocol;
> + EFI_BLOCK_IO_MEDIA Media;
> + EFI_DISK_IO_PROTOCOL DiskIoProtocol;
> +
> + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
> + VOID* ShadowBuffer;
> +
> + NOR_FLASH_DEVICE_PATH DevicePath;
> +
> + CONST CSDC_DEFINITION *CmdTable;
> + UINTN CmdTableSize;
> +
> + UINT32 Flags;
> +#define NOR_FLASH_POLL_FSR BIT0
> +};
> +
> +EFI_STATUS
> +NorFlashReadCfiData (
> + IN UINTN DeviceBaseAddress,
> + IN UINTN CFI_Offset,
> + IN UINT32 NumberOfBytes,
> + OUT UINT32 *Data
> + );
> +
> +EFI_STATUS
> +NorFlashWriteBuffer (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN TargetAddress,
> + IN UINTN BufferSizeInBytes,
> + IN UINT32 *Buffer
> + );
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoReset (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN BOOLEAN ExtendedVerification
> + );
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoReadBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> +);
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoWriteBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + IN VOID *Buffer
> +);
> +
> +//
> +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks
> +//
> +EFI_STATUS
> +EFIAPI
> +NorFlashBlockIoFlushBlocks (
> + IN EFI_BLOCK_IO_PROTOCOL *This
> +);
> +
> +//
> +// NorFlashFvbDxe.c
> +//
> +
> +EFI_STATUS
> +EFIAPI
> +NorFlashFvbInitialize (
> + IN NOR_FLASH_INSTANCE* Instance
> + );
> +
> +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,
> + ...
> + );
> +
> +//
> +// NorFlashDxe.c
> +//
> +
> +EFI_STATUS
> +NorFlashUnlockAndEraseSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN UINTN BlockAddress
> + );
> +
> +EFI_STATUS
> +NorFlashWriteSingleBlock (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN OUT UINTN *NumBytes,
> + IN UINT8 *Buffer
> + );
> +
> +EFI_STATUS
> +NorFlashWriteBlocks (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + IN VOID *Buffer
> + );
> +
> +EFI_STATUS
> +NorFlashReadBlocks (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> + );
> +
> +EFI_STATUS
> +NorFlashRead (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN UINTN BufferSizeInBytes,
> + OUT VOID *Buffer
> + );
> +
> +EFI_STATUS
> +NorFlashWrite (
> + IN NOR_FLASH_INSTANCE *Instance,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN OUT UINTN *NumBytes,
> + IN UINT8 *Buffer
> + );
> +
> +EFI_STATUS
> +NorFlashReset (
> + IN NOR_FLASH_INSTANCE *Instance
> + );
> +
> +EFI_STATUS
> +NorFlashReadID (
> + IN NOR_FLASH_INSTANCE *Instance,
> + OUT UINT8 JedecId[3]
> + );
> +
> +#endif /* __NOR_FLASH_DXE_H__ */
> diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c
> new file mode 100644
> index 000000000000..6984711df609
> --- /dev/null
> +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c
> @@ -0,0 +1,859 @@
> +/** @file NorFlashFvbDxe.c
> +
> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
> +
> + This program and the accompanying materials are licensed and made available
> + under the terms and conditions of the BSD License which accompanies this
> + distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> + --*/
> +
> +#include <PiDxe.h>
> +
> +#include <Library/PcdLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <Guid/VariableFormat.h>
> +#include <Guid/SystemNvDataGuid.h>
Sorted, please.
> +
> +#include "NorFlashDxe.h"
> +
> +STATIC EFI_EVENT mFvbVirtualAddrChangeEvent;
> +STATIC UINTN mFlashNvStorageVariableBase;
> +
> +///
> +/// The Firmware Volume Block Protocol is the low-level interface
> +/// to a firmware volume. File-level access to a firmware volume
> +/// should not be done using the Firmware Volume Block Protocol.
> +/// Normal access to a firmware volume must use the Firmware
> +/// Volume Protocol. Typically, only the file system driver that
> +/// produces the Firmware Volume Protocol will bind to the
> +/// Firmware Volume Block Protocol.
> +///
> +
> +/**
> + Initialises the FV Header and Variable Store Header
> + to support variable operations.
> +
> + @param[in] Ptr - Location to initialise the headers
> +
> +**/
> +STATIC
> +EFI_STATUS
> +InitializeFvAndVariableStoreHeaders (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + EFI_STATUS Status;
> + VOID* Headers;
> + UINTN HeadersLength;
> + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
> + VARIABLE_STORE_HEADER *VariableStoreHeader;
> + UINTN BlockSize;
> +
> + if (!Instance->Initialized && Instance->Initialize) {
> + Instance->Initialize (Instance);
> + }
> +
> + HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
> + sizeof(EFI_FV_BLOCK_MAP_ENTRY) +
> + sizeof(VARIABLE_STORE_HEADER);
> + Headers = AllocateZeroPool(HeadersLength);
> +
> + BlockSize = Instance->Media.BlockSize;
> +
> + // FirmwareVolumeHeader->FvLength is declared to have the Variable area
> + // AND the FTW working area AND the FTW Spare contiguous.
> + ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) +
> + PcdGet32(PcdFlashNvStorageVariableSize) ==
> + PcdGet32(PcdFlashNvStorageFtwWorkingBase));
> + ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) +
> + PcdGet32(PcdFlashNvStorageFtwWorkingSize) ==
> + PcdGet32(PcdFlashNvStorageFtwSpareBase));
> +
> + // Check if the size of the 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((PcdGet32(PcdFlashNvStorageVariableBase) % BlockSize) == 0);
> + ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0);
> + ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0);
> +
> + //
> + // EFI_FIRMWARE_VOLUME_HEADER
> + //
> + FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
> + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
> + FirmwareVolumeHeader->FvLength =
> + PcdGet32(PcdFlashNvStorageVariableSize) +
> + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
> + PcdGet32(PcdFlashNvStorageFtwSpareSize);
> + FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
> + FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
> + EFI_FVB2_READ_STATUS |
> + EFI_FVB2_STICKY_WRITE |
> + EFI_FVB2_MEMORY_MAPPED |
> + EFI_FVB2_ERASE_POLARITY |
> + EFI_FVB2_WRITE_STATUS |
> + EFI_FVB2_WRITE_ENABLED_CAP;
> +
> + FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
> + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
> + FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
> + FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;
> + FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;
> + FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
> + FirmwareVolumeHeader->BlockMap[1].Length = 0;
> + FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
> + (UINT16*)FirmwareVolumeHeader,
> + FirmwareVolumeHeader->HeaderLength);
> +
> + //
> + // 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;
> +
> + // Install the combined super-header in the NorFlash
> + Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
> +
> + FreePool (Headers);
> + return Status;
> +}
> +
> +/**
> + Check the integrity of firmware volume header.
> +
> + @param[in] FwVolHeader - A pointer to a firmware volume header
> +
> + @retval EFI_SUCCESS - The firmware volume is consistent
> + @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
> +
> +**/
> +EFI_STATUS
> +ValidateFvHeader (
> + IN NOR_FLASH_INSTANCE *Instance
> + )
> +{
> + UINT16 Checksum;
> + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
> + VARIABLE_STORE_HEADER *VariableStoreHeader;
> + UINTN VariableStoreLength;
> + UINTN FvLength;
> +
> + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress;
> +
> + FvLength = PcdGet32(PcdFlashNvStorageVariableSize) +
> + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
> + PcdGet32(PcdFlashNvStorageFtwSpareSize);
> +
> + //
> + // Verify the header revision, header signature, length
> + // Length of FvBlock cannot be 2**64-1
> + // HeaderLength cannot be an odd number
> + //
> + if ( (FwVolHeader->Revision != EFI_FVH_REVISION)
> + || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
> + || (FwVolHeader->FvLength != FvLength)
> + )
> + {
> + DEBUG ((DEBUG_INFO, "%a: No Firmware Volume header present\n",
> + __FUNCTION__));
> + return EFI_NOT_FOUND;
> + }
> +
> + // Check the Firmware Volume Guid
> + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
> + DEBUG ((DEBUG_INFO, "%a: Firmware Volume Guid non-compatible\n",
> + __FUNCTION__));
> + return EFI_NOT_FOUND;
> + }
> +
> + // Verify the header checksum
> + Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
> + if (Checksum != 0) {
> + DEBUG ((DEBUG_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n",
> + __FUNCTION__, Checksum));
> + return EFI_NOT_FOUND;
> + }
> +
> + VariableStoreHeader = (VOID *)((UINTN)FwVolHeader +
> + FwVolHeader->HeaderLength);
> +
> + // Check the Variable Store Guid
> + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
> + !CompareGuid (&VariableStoreHeader->Signature,
> + &gEfiAuthenticatedVariableGuid)) {
> + DEBUG ((DEBUG_INFO, "%a: Variable Store Guid non-compatible\n",
> + __FUNCTION__));
> + return EFI_NOT_FOUND;
> + }
> +
> + VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
> + FwVolHeader->HeaderLength;
> + if (VariableStoreHeader->Size != VariableStoreLength) {
> + DEBUG ((DEBUG_INFO, "%a: Variable Store Length does not match\n",
> + __FUNCTION__));
> + return EFI_NOT_FOUND;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The GetAttributes() function retrieves the attributes and
> + current settings of the block.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
> + current settings are returned.
> + Type EFI_FVB_ATTRIBUTES_2 is defined in
> + EFI_FIRMWARE_VOLUME_HEADER.
> +
> + @retval EFI_SUCCESS The firmware volume attributes were returned.
> +
> + **/
> +EFI_STATUS
> +EFIAPI
> +FvbGetAttributes(
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes
> + )
> +{
> + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS(This);
> +
> + FlashFvbAttributes = EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS |
> + EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED |
> + EFI_FVB2_ERASE_POLARITY;
> +
> + // Check if it is write protected
> + if (!Instance->Media.ReadOnly) {
> + FlashFvbAttributes |= EFI_FVB2_WRITE_STATUS | EFI_FVB2_WRITE_ENABLED_CAP;
> + }
> +
> + *Attributes = FlashFvbAttributes;
> +
> + DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The SetAttributes() function sets configurable firmware volume attributes
> + and returns the new settings of the firmware volume.
> +
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Attributes On input, Attributes is a pointer to
> + EFI_FVB_ATTRIBUTES_2 that contains the desired
> + firmware volume settings.
> + On successful return, it contains the new
> + settings of the firmware volume.
> +
> + @retval EFI_SUCCESS The firmware volume attributes were returned.
> +
> + @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
> + the capabilities as declared in the firmware
> + volume header.
> +
> + **/
> +EFI_STATUS
> +EFIAPI
> +FvbSetAttributes(
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
> + )
> +{
> + DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",
> + *Attributes));
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + The GetPhysicalAddress() function retrieves the base address of
> + a memory-mapped firmware volume. This function should be called
> + only for memory-mapped firmware volumes.
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Address Pointer to a caller-allocated
> + EFI_PHYSICAL_ADDRESS that, on successful
> + return from GetPhysicalAddress(), contains the
> + base address of the firmware volume.
> +
> + @retval EFI_SUCCESS The firmware volume base address was returned.
> +
> + @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
> +
> + **/
> +EFI_STATUS
> +EFIAPI
> +FvbGetPhysicalAddress (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + OUT EFI_PHYSICAL_ADDRESS *Address
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n",
> + Instance->RegionBaseAddress));
> +
> + ASSERT(Address != NULL);
> +
> + *Address = Instance->RegionBaseAddress;
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The GetBlockSize() function retrieves the size of the requested
> + block. It also returns the number of additional blocks with
> + the identical size. The GetBlockSize() function is used to
> + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
> +
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba Indicates the block whose size to return
> +
> + @param BlockSize Pointer to a caller-allocated UINTN in which
> + the size of the block is returned.
> +
> + @param NumberOfBlocks Pointer to a caller-allocated UINTN in
> + which the number of consecutive blocks,
> + starting with Lba, is returned. All
> + blocks in this range have a size of
> + BlockSize.
> +
> +
> + @retval EFI_SUCCESS The firmware volume base address was returned.
> +
> + @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
> +
> + **/
> +EFI_STATUS
> +EFIAPI
> +FvbGetBlockSize (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN EFI_LBA Lba,
> + OUT UINTN *BlockSize,
> + OUT UINTN *NumberOfBlocks
> + )
> +{
> + EFI_STATUS Status;
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO,
> + "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba,
> + Instance->Media.BlockSize, Instance->Media.LastBlock));
> +
> + if (Lba > Instance->Media.LastBlock) {
> + DEBUG ((DEBUG_ERROR,
> + "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n",
> + Lba, Instance->Media.LastBlock));
> + Status = EFI_INVALID_PARAMETER;
> + } else {
> + // This is easy because in this platform each NorFlash device has equal sized blocks.
> + *BlockSize = (UINTN) Instance->Media.BlockSize;
> + *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1);
> +
> + DEBUG ((DEBUG_BLKIO,
> + "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize,
> + *NumberOfBlocks));
> +
> + Status = EFI_SUCCESS;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Reads the specified number of bytes into a buffer from the specified block.
> +
> + The Read() function reads the requested number of bytes from the
> + requested block and stores them in the provided buffer.
> + Implementations should be mindful that the firmware volume
> + might be in the ReadDisabled state. If it is in this state,
> + the Read() function must return the status code
> + EFI_ACCESS_DENIED without modifying the contents of the
> + buffer. The Read() function must also prevent spanning block
> + boundaries. If a read is requested that would span a block
> + boundary, the read must read up to the boundary but not
> + beyond. The output parameter NumBytes must be set to correctly
> + indicate the number of bytes actually read. The caller must be
> + aware that a read may be partially completed.
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba The starting logical block index from which to read
> +
> + @param Offset Offset into the block at which to begin reading.
> +
> + @param NumBytes Pointer to a UINTN.
> + At entry, *NumBytes contains the total size of the
> + buffer.
> + At exit, *NumBytes contains the total number of
> + bytes read.
> +
> + @param Buffer Pointer to a caller-allocated buffer that will be
> + used to hold the data that is read.
> +
> + @retval EFI_SUCCESS The firmware volume was read successfully, and
> + contents are in Buffer.
> +
> + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
> + On output, NumBytes contains the total number of
> + bytes returned in Buffer.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
> +
> + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
> + could not be read.
> +
> + **/
> +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 TempStatus;
> + UINTN BlockSize;
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO,
> + "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
> + Instance->StartLba + Lba, Offset, *NumBytes, Buffer));
> +
> + if (!Instance->Initialized && Instance->Initialize) {
> + Instance->Initialize(Instance);
> + }
> +
> + TempStatus = EFI_SUCCESS;
> +
> + // Cache the block size to avoid de-referencing pointers all the time
> + BlockSize = Instance->Media.BlockSize;
> +
> + DEBUG ((DEBUG_BLKIO,
> + "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n",
> + Offset, *NumBytes, BlockSize ));
> +
> + // The read must not span block boundaries.
> + // We need to check each variable individually because adding two large
> + // values together overflows.
> + if (Offset >= BlockSize ||
> + *NumBytes > BlockSize ||
> + (Offset + *NumBytes) > BlockSize) {
> + DEBUG ((DEBUG_ERROR,
> + "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
> + Offset, *NumBytes, BlockSize ));
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // We must have some bytes to read
> + if (*NumBytes == 0) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + // Decide if we are doing full block reads or not.
> + if (*NumBytes % BlockSize != 0) {
> + TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset,
> + *NumBytes, Buffer);
> + if (EFI_ERROR (TempStatus)) {
> + return EFI_DEVICE_ERROR;
> + }
> + } else {
> + // Read NOR Flash data into shadow buffer
> + TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba,
> + BlockSize, Buffer);
> + if (EFI_ERROR (TempStatus)) {
> + // Return one of the pre-approved error statuses
> + return EFI_DEVICE_ERROR;
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Writes the specified number of bytes from the input buffer to the block.
> +
> + The Write() function writes the specified number of bytes from
> + the provided buffer to the specified block and offset. If the
> + firmware volume is sticky write, the caller must ensure that
> + all the bits of the specified range to write are in the
> + EFI_FVB_ERASE_POLARITY state before calling the Write()
> + function, or else the result will be unpredictable. This
> + unpredictability arises because, for a sticky-write firmware
> + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
> + state but cannot flip it back again. Before calling the
> + Write() function, it is recommended for the caller to first call
> + the EraseBlocks() function to erase the specified block to
> + write. A block erase cycle will transition bits from the
> + (NOT)EFI_FVB_ERASE_POLARITY state back to the
> + EFI_FVB_ERASE_POLARITY state. Implementations should be
> + mindful that the firmware volume might be in the WriteDisabled
> + state. If it is in this state, the Write() function must
> + return the status code EFI_ACCESS_DENIED without modifying the
> + contents of the firmware volume. The Write() function must
> + also prevent spanning block boundaries. If a write is
> + requested that spans a block boundary, the write must store up
> + to the boundary but not beyond. The output parameter NumBytes
> + must be set to correctly indicate the number of bytes actually
> + written. The caller must be aware that a write may be
> + partially completed. All writes, partial or otherwise, must be
> + fully flushed to the hardware before the Write() service
> + returns.
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba The starting logical block index to write to.
> +
> + @param Offset Offset into the block at which to begin writing.
> +
> + @param NumBytes The pointer to a UINTN.
> + At entry, *NumBytes contains the total size of the
> + buffer.
> + At exit, *NumBytes contains the total number of
> + bytes actually written.
> +
> + @param Buffer The pointer to a caller-allocated buffer that
> + contains the source for the write.
> +
> + @retval EFI_SUCCESS The firmware volume was written successfully.
> +
> + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
> + On output, NumBytes contains the total number of
> + bytes actually written.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
> +
> + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be
> + written.
> +
> +
> + **/
> +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
> + )
> +{
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS (This);
> +
> + return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset,
> + NumBytes, Buffer);
> +}
> +
> +/**
> + Erases and initialises a firmware volume block.
> +
> + The EraseBlocks() function erases one or more blocks as denoted
> + by the variable argument list. The entire parameter list of
> + blocks must be verified before erasing any blocks. If a block is
> + requested that does not exist within the associated firmware
> + volume (it has a larger index than the last block of the
> + firmware volume), the EraseBlocks() function must return the
> + status code EFI_INVALID_PARAMETER without modifying the contents
> + of the firmware volume. Implementations should be mindful that
> + the firmware volume might be in the WriteDisabled state. If it
> + is in this state, the EraseBlocks() function must return the
> + status code EFI_ACCESS_DENIED without modifying the contents of
> + the firmware volume. All calls to EraseBlocks() must be fully
> + flushed to the hardware before the EraseBlocks() service
> + returns.
> +
> + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
> + instance.
> +
> + @param ... The variable argument list is a list of tuples.
> + Each tuple describes a range of LBAs to erase
> + and consists of the following:
> + - An EFI_LBA that indicates the starting LBA
> + - A UINTN that indicates the number of blocks
> + to erase.
> +
> + The list is terminated with an
> + EFI_LBA_LIST_TERMINATOR.
> +
> + @retval EFI_SUCCESS The erase request successfully completed.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
> + state.
> +
> + @retval EFI_DEVICE_ERROR The block device is not functioning correctly
> + and could not be written.
> + The firmware device may have been partially
> + erased.
> +
> + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
> + argument list do not exist in the firmware
> + volume.
> +
> + **/
> +EFI_STATUS
> +EFIAPI
> +FvbEraseBlocks (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + ...
> + )
> +{
> + 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
> + NOR_FLASH_INSTANCE *Instance;
> +
> + Instance = INSTANCE_FROM_FVB_THIS(This);
> +
> + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n"));
> +
> + Status = EFI_SUCCESS;
> +
> + // Detect WriteDisabled state
> + if (Instance->Media.ReadOnly) {
> + // Firmware volume is in WriteDisabled state
> + DEBUG ((DEBUG_ERROR,
> + "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));
> + 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) {
> + //Exit the while loop
> + break;
> + }
> +
> + // How many Lba blocks are we requested to erase?
> + NumOfLba = VA_ARG (Args, UINT32);
> +
> + // All blocks must be within range
> + DEBUG ((DEBUG_BLKIO,
> + "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n",
> + Instance->StartLba + StartingLba, NumOfLba, Instance->Media.LastBlock));
> + if (NumOfLba == 0 ||
> + (Instance->StartLba + StartingLba + NumOfLba - 1) >
> + Instance->Media.LastBlock) {
> + VA_END (Args);
> + DEBUG ((DEBUG_ERROR,
> + "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
> + Status = EFI_INVALID_PARAMETER;
> + goto EXIT;
> + }
> + } while (TRUE);
> + VA_END (Args);
> +
> + //
> + // To get here, all must be ok, so 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) {
> + // Exit the while loop
> + break;
> + }
> +
> + // How many Lba blocks are we requested to erase?
> + NumOfLba = VA_ARG (Args, UINT32);
> +
> + // Go through each one and erase it
> + while (NumOfLba > 0) {
> +
> + // Get the physical address of Lba to erase
> + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
> + Instance->StartLba + StartingLba,
> + Instance->Media.BlockSize);
> +
> + // Erase it
> + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n",
> + Instance->StartLba + StartingLba, BlockAddress));
> + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
> + if (EFI_ERROR(Status)) {
> + VA_END (Args);
> + Status = EFI_DEVICE_ERROR;
> + goto EXIT;
> + }
> +
> + // Move to the next Lba
> + StartingLba++;
> + NumOfLba--;
> + }
> + } while (TRUE);
> + VA_END (Args);
> +
> +EXIT:
> + return Status;
> +}
> +
> +/**
> + Fixup internal data so that EFI can be call in virtual mode.
> + Call the passed in Child Notify event and convert any pointers in
> + lib to virtual mode.
> +
> + @param[in] Event The Event that is being processed
> + @param[in] Context Event Context
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +FvbVirtualNotifyEvent (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
> + return;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +NorFlashFvbInitialize (
> + IN NOR_FLASH_INSTANCE* Instance
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 FvbNumLba;
> + EFI_BOOT_MODE BootMode;
> + UINTN RuntimeMmioRegionSize;
> +
> + DEBUG ((DEBUG_BLKIO,"NorFlashFvbInitialize\n"));
> +
> + Instance->Initialized = TRUE;
> + mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
> +
> + // Set the index of the first LBA for the FVB
> + Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) -
> + Instance->RegionBaseAddress) /
> + Instance->Media.BlockSize;
> +
> + BootMode = GetBootModeHob ();
> + if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
> + Status = EFI_INVALID_PARAMETER;
> + } else {
> + // Determine if there is a valid header at the beginning of the NorFlash
> + Status = ValidateFvHeader (Instance);
> + }
> +
> + // Install the Default FVB header if required
> + if (EFI_ERROR(Status)) {
> + // There is no valid header, so time to install one.
> + DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));
> + DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n",
> + __FUNCTION__));
> +
> + // Erase all the NorFlash that is reserved for variable storage
> + FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) +
> + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
> + PcdGet32(PcdFlashNvStorageFtwSpareSize)) /
> + Instance->Media.BlockSize;
No need to deal with spill? Or ASSERTs for lacking alignment to
BlockSize?
> +
> + Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba,
> + EFI_LBA_LIST_TERMINATOR);
> + if (EFI_ERROR(Status)) {
> + return Status;
> + }
> +
> + // Install all appropriate headers
> + Status = InitializeFvAndVariableStoreHeaders (Instance);
> + if (EFI_ERROR(Status)) {
> + return Status;
> + }
> + }
> +
> + //
> + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
> + //
> + RuntimeMmioRegionSize = Instance->Size;
> +
> + Status = gDS->AddMemorySpace (
> + EfiGcdMemoryTypeMemoryMappedIo,
> + Instance->RegionBaseAddress, RuntimeMmioRegionSize,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> + );
Indentation incorrect (also for several subsequent statements).
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gDS->AddMemorySpace (
> + EfiGcdMemoryTypeMemoryMappedIo,
> + Instance->DeviceBaseAddress, SIZE_4KB,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gDS->SetMemorySpaceAttributes (
> + Instance->RegionBaseAddress, RuntimeMmioRegionSize,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gDS->SetMemorySpaceAttributes (
> + Instance->DeviceBaseAddress, SIZE_4KB,
> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
> + ASSERT_EFI_ERROR (Status);
/
Leif
> +
> + //
> + // Register for the virtual address change event
> + //
> + Status = gBS->CreateEventEx (
> + EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + FvbVirtualNotifyEvent,
> + NULL,
> + &gEfiEventVirtualAddressChangeGuid,
> + &mFvbVirtualAddrChangeEvent
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + return Status;
> +}
> --
> 2.11.0
>
next prev parent reply other threads:[~2017-10-26 21:16 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-25 17:59 [PATCH edk2-platforms v2 00/23] add support for Socionext Synquacer Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 01/23] Silicon/SynQuacer: add package with platform headers Ard Biesheuvel
2017-10-26 14:39 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 02/23] Silicon/Socionext: add driver for NETSEC network controller Ard Biesheuvel
2017-10-26 14:49 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 03/23] Silicon/SynQuacer: add MemoryInitPeiLib implementation Ard Biesheuvel
2017-10-26 14:56 ` Leif Lindholm
2017-10-26 14:57 ` Ard Biesheuvel
2017-10-26 15:05 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 04/23] Platform: add support for Socionext SynQuacer eval board Ard Biesheuvel
2017-10-26 15:02 ` Leif Lindholm
2017-10-26 15:14 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 05/23] Silicon/SynQuacer: implement PciSegmentLib to support dual RCs Ard Biesheuvel
2017-10-26 15:06 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 06/23] Silicon/SynQuacer: implement PciHostBridgeLib support Ard Biesheuvel
2017-10-26 15:10 ` Leif Lindholm
2017-10-26 15:12 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 07/23] Silicon/SynQuacer: implement EFI_CPU_IO2_PROTOCOL Ard Biesheuvel
2017-10-26 15:13 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 08/23] Platform/SynQuacerEvalBoard: add PCI support Ard Biesheuvel
2017-10-26 15:38 ` Leif Lindholm
2017-10-26 15:41 ` Ard Biesheuvel
2017-10-26 21:49 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 09/23] Platform/SynQuacerEvalBoard: add NETSEC driver Ard Biesheuvel
2017-10-26 15:39 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 10/23] Silicon/SynQuacer: add ACPI support Ard Biesheuvel
2017-10-26 17:13 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 11/23] Silicon/SynQuacer: add device tree support for eval board Ard Biesheuvel
2017-10-26 17:15 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 12/23] Silicon/SynQuacer: add NorFlashPlatformLib implementation Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 13/23] Silicon/Socionext: add driver for SPI NOR flash Ard Biesheuvel
2017-10-26 21:19 ` Leif Lindholm [this message]
2017-10-28 14:16 ` Ard Biesheuvel
2017-10-28 21:31 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 14/23] Platform/SynQuacer: incorporate NOR flash and variable drivers Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 15/23] Silicon/SynQuacer: implement PlatformFlashAccessLib Ard Biesheuvel
2017-10-26 21:22 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 16/23] SynQuacer/SynQuacerMemoryInitPeiLib: add capsule support Ard Biesheuvel
2017-10-26 21:27 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 17/23] Socionext/SynQuacerEvalBoard: wire up basic " Ard Biesheuvel
2017-10-26 21:28 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 18/23] Socionext/SynQuacerEvalBoard: switch to execute in place Ard Biesheuvel
2017-10-26 21:30 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 19/23] Platform/SynQuacerEvalBoard: add signed capsule update support Ard Biesheuvel
2017-10-26 21:33 ` Leif Lindholm
2017-10-28 13:48 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 20/23] Silicon/SynQuacer/AcpiTables: hide PCI domain #0 Ard Biesheuvel
2017-10-26 21:34 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 21/23] Silicon/SynQuacerPciHostBridgeLib: add workaround to support 32-bit only cards Ard Biesheuvel
2017-10-26 21:35 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 22/23] Platform/Socionext: add support for Socionext Developer Box rev 0.1 Ard Biesheuvel
2017-10-26 21:46 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 23/23] Platform/DeveloperBox: add ConsolePrefDxe driver Ard Biesheuvel
2017-10-26 21:46 ` Leif Lindholm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox