From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=92.121.34.13; helo=inva020.nxp.com; envelope-from=meenakshi.aggarwal@nxp.com; receiver=edk2-devel@lists.01.org Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 3EDF021E11D1A for ; Wed, 28 Nov 2018 01:16:24 -0800 (PST) Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id E7FAC1A0303; Wed, 28 Nov 2018 10:16:22 +0100 (CET) Received: from inv0113.in-blr01.nxp.com (inv0113.in-blr01.nxp.com [165.114.116.118]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id AE05D1A0302; Wed, 28 Nov 2018 10:16:21 +0100 (CET) Received: from uefi-OptiPlex-790.ap.freescale.net (uefi-OptiPlex-790.ap.freescale.net [10.232.132.78]) by inv0113.in-blr01.nxp.com (Postfix) with ESMTP id C0C8D35F; Wed, 28 Nov 2018 14:46:20 +0530 (IST) From: Meenakshi Aggarwal To: ard.biesheuvel@linaro.org, leif.lindholm@linaro.org, michael.d.kinney@intel.com, edk2-devel@lists.01.org Date: Wed, 28 Nov 2018 20:31:31 +0530 Message-Id: <1543417315-5763-18-git-send-email-meenakshi.aggarwal@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1543417315-5763-1-git-send-email-meenakshi.aggarwal@nxp.com> References: <1518771035-6733-1-git-send-email-meenakshi.aggarwal@nxp.com> <1543417315-5763-1-git-send-email-meenakshi.aggarwal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH edk2-platforms 17/41] Silicon/NXP : Add NOR driver. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Nov 2018 09:16:24 -0000 Add NOR DXE phase driver, it installs BlockIO and Fvp protocol. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Meenakshi Aggarwal --- Platform/NXP/LS1043aRdbPkg/VarStore.fdf.inc | 98 +++ .../NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c | 252 +++++++ Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c | 503 +++++++++++++ Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h | 146 ++++ Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf | 65 ++ Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 816 +++++++++++++++++++++ 6 files changed, 1880 insertions(+) create mode 100644 Platform/NXP/LS1043aRdbPkg/VarStore.fdf.inc create mode 100644 Silicon/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c create mode 100644 Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c create mode 100644 Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h create mode 100644 Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf create mode 100644 Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c diff --git a/Platform/NXP/LS1043aRdbPkg/VarStore.fdf.inc b/Platform/NXP/LS1043aRdbPkg/VarStore.fdf.inc new file mode 100644 index 0000000..e254337 --- /dev/null +++ b/Platform/NXP/LS1043aRdbPkg/VarStore.fdf.inc @@ -0,0 +1,98 @@ +## @file +# FDF include file with FD definition that defines an empty variable store. +# +# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved. +# Copyright (C) 2014, Red Hat, Inc. +# Copyright (c) 2016, Linaro, Ltd. All rights reserved. +# Copyright (c) 2016, Freescale Semiconductor. All rights reserved. +# Copyright 2017 NXP +# +# 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. +# +## + +[FD.LS1043aRdbNv_EFI] +BaseAddress = 0x60300000 #The base address of the FLASH device +Size = 0x000C0000 #The size in bytes of the FLASH device +ErasePolarity = 1 +BlockSize = 0x1 +NumBlocks = 0xC0000 + +# +# Place NV Storage just above Platform Data Base +# +DEFINE NVRAM_AREA_VARIABLE_BASE = 0x00000000 +DEFINE NVRAM_AREA_VARIABLE_SIZE = 0x00040000 +DEFINE FTW_WORKING_BASE = $(NVRAM_AREA_VARIABLE_BASE) + $(NVRAM_AREA_VARIABLE_SIZE) +DEFINE FTW_WORKING_SIZE = 0x00040000 +DEFINE FTW_SPARE_BASE = $(FTW_WORKING_BASE) + $(FTW_WORKING_SIZE) +DEFINE FTW_SPARE_SIZE = 0x00040000 + +############################################################################# +# LS1043ARDB NVRAM Area +# LS1043ARDB NVRAM Area contains: Variable + FTW Working + FTW Spare +############################################################################# + + +$(NVRAM_AREA_VARIABLE_BASE)|$(NVRAM_AREA_VARIABLE_SIZE) +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize +#NV_VARIABLE_STORE +DATA = { + ## This is the EFI_FIRMWARE_VOLUME_HEADER + # ZeroVector [] + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + # FileSystemGuid: gEfiSystemNvDataFvGuid = + # { 0xFFF12B8D, 0x7696, 0x4C8B, + # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }} + 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, + 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50, + # FvLength: 0xC0000 + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + # Signature "_FVH" # Attributes + 0x5f, 0x46, 0x56, 0x48, 0x36, 0x0E, 0x00, 0x00, + # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision + 0x48, 0x00, 0xC2, 0xF9, 0x00, 0x00, 0x00, 0x02, + # Blockmap[0]: 0x3 Blocks * 0x40000 Bytes / Block + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + # Blockmap[1]: End + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ## This is the VARIABLE_STORE_HEADER + # It is compatible with SECURE_BOOT_ENABLE == FALSE as well. + # Signature: gEfiAuthenticatedVariableGuid = + # { 0xaaf32c78, 0x947b, 0x439a, + # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }} + 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, + 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92, + # Size: 0x40000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) - + # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x3ffb8 + # This can speed up the Variable Dispatch a bit. + 0xB8, 0xFF, 0x03, 0x00, + # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32 + 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +$(FTW_WORKING_BASE)|$(FTW_WORKING_SIZE) +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize +#NV_FTW_WORKING +DATA = { + # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid = + # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} + 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49, + 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95, + # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved + 0x5b, 0xe7, 0xc6, 0x86, 0xFE, 0xFF, 0xFF, 0xFF, + # WriteQueueSize: UINT64 + 0xE0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +$(FTW_SPARE_BASE)|$(FTW_SPARE_SIZE) +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize +#NV_FTW_SPARE diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c new file mode 100644 index 0000000..bc49fdc --- /dev/null +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c @@ -0,0 +1,252 @@ +/** @NorFlashBlockIoDxe.c + + Based on NorFlash implementation available in + ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + 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 +#include + +#include +#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_INFO, "NorFlashBlockIoReset (MediaId=0x%x)\n", + This->Media->MediaId)); + + return NorFlashPlatformReset (Instance->DeviceBaseAddress); +} + +// +// 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; + UINTN NumBlocks; + UINT8 *ReadBuffer; + UINTN BlockCount; + UINTN BlockSizeInBytes; + EFI_LBA CurrentBlock; + + Status = EFI_SUCCESS; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = INSTANCE_FROM_BLKIO_THIS (This); + Media = This->Media; + + if (Media == NULL) { + DEBUG ((DEBUG_ERROR, "%a : Media is NULL\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + NumBlocks = BufferSizeInBytes / Instance->Media.BlockSize ; + + DEBUG ((DEBUG_BLKIO, + "%a : (MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%p)\n", + __FUNCTION__, MediaId, Lba, BufferSizeInBytes, Buffer)); + + if (!Media->MediaPresent) { + return EFI_NO_MEDIA; + } + if (Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + if ((Media->IoAlign >= 2) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + if (BufferSizeInBytes == 0) { + // Return if we have not any byte to read + return EFI_SUCCESS; + } + if ((BufferSizeInBytes % Media->BlockSize) != 0) { + // The size of the buffer must be a multiple of the block size + DEBUG ((DEBUG_ERROR, "%a : BlockSize in bytes = 0x%x\n", __FUNCTION__, BufferSizeInBytes)); + return EFI_INVALID_PARAMETER; + } + if ((Lba + NumBlocks - 1) > Media->LastBlock) { + // All blocks must be within the device + DEBUG ((DEBUG_ERROR, "%a : Read will exceed last block %d, %d, %d \n", + __FUNCTION__, Lba, NumBlocks, Media->LastBlock)); + return EFI_INVALID_PARAMETER; + } + + BlockSizeInBytes = Instance->Media.BlockSize; + + /* 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 */ + ReadBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Read data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++) { + DEBUG ((DEBUG_BLKIO, "%a: Reading block #%d\n", __FUNCTION__, (UINTN)CurrentBlock)); + + Status = NorFlashPlatformRead (Instance, CurrentBlock, (UINTN)0 , + BlockSizeInBytes, ReadBuffer); + if (EFI_ERROR (Status)) { + break; + } + + CurrentBlock++; + ReadBuffer = ReadBuffer + BlockSizeInBytes; + } + + 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; + EFI_BLOCK_IO_MEDIA *Media; + UINTN NumBlocks; + EFI_LBA CurrentBlock; + UINTN BlockSizeInBytes; + UINT32 BlockCount; + UINTN SectorAddress; + UINT8 *WriteBuffer; + + Status = EFI_SUCCESS; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = INSTANCE_FROM_BLKIO_THIS (This); + Media = This->Media; + + if (Media == NULL) { + DEBUG ((DEBUG_ERROR, "%a : Media is NULL\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + NumBlocks = BufferSizeInBytes / Instance->Media.BlockSize ; + + DEBUG ((DEBUG_BLKIO, + "%a : (MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB) BufferPtr @ 0x%08x)\n", + __FUNCTION__, MediaId, Lba, BufferSizeInBytes, Buffer)); + + if (!Media->MediaPresent) { + return EFI_NO_MEDIA; + } + if (Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + if (Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + if (BufferSizeInBytes == 0) { + return EFI_BAD_BUFFER_SIZE; + } + if ((BufferSizeInBytes % Media->BlockSize) != 0) { + // The size of the buffer must be a multiple of the block size + DEBUG ((DEBUG_ERROR, "%a : BlockSize in bytes = 0x%x\n",__FUNCTION__, BufferSizeInBytes)); + return EFI_INVALID_PARAMETER; + } + if ((Lba + NumBlocks - 1) > Media->LastBlock) { + // All blocks must be within the device + DEBUG ((DEBUG_ERROR, "%a: Write will exceed last block %d, %d, %d \n", + __FUNCTION__,Lba, NumBlocks, Media->LastBlock)); + return EFI_INVALID_PARAMETER; + } + + BlockSizeInBytes = Instance->Media.BlockSize; + + WriteBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Program data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++) { + DEBUG ((DEBUG_BLKIO, "%a: Writing block #%d\n", __FUNCTION__, (UINTN)CurrentBlock)); + // Erase the Block(Sector) to be written to + SectorAddress = GET_NOR_BLOCK_ADDRESS ( + Instance->RegionBaseAddress, + CurrentBlock, + Instance->Media.BlockSize + ); + + Status = NorFlashPlatformEraseSector (Instance, (UINTN)SectorAddress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to erase Target 0x%x (0x%x) \n", + __FUNCTION__,SectorAddress, Status)); + break; + } + + // Program Block(Sector) to be written to + Status = NorFlashWrite (Instance, CurrentBlock, (UINTN)0, &BlockSizeInBytes, WriteBuffer); + if (EFI_ERROR (Status)) { + break; + } + + CurrentBlock++; + WriteBuffer = WriteBuffer + BlockSizeInBytes; + } + + return Status; +} + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + DEBUG ((DEBUG_BLKIO, "%a NOT IMPLEMENTED (not required)\n", __FUNCTION__)); + + // Nothing to do so just return without error + return EFI_SUCCESS; +} diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c new file mode 100644 index 0000000..ab94662 --- /dev/null +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c @@ -0,0 +1,503 @@ +/** @file + + Based on NorFlash implementation available in + ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + 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 +#include +#include +#include +#include +#include +#include + +#include "NorFlashDxe.h" + +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; + +// +// Global variable declarations +// +NOR_FLASH_INSTANCE **mNorFlashInstances; +UINT32 mNorFlashDeviceCount; + +NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { + .Signature = NOR_FLASH_SIGNATURE, + .StartLba = 0, + .BlockIoProtocol = { + .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2, + .Reset = NorFlashBlockIoReset, + .ReadBlocks = NorFlashBlockIoReadBlocks, + .WriteBlocks = NorFlashBlockIoWriteBlocks, + .FlushBlocks = NorFlashBlockIoFlushBlocks, + }, + + .Media = { + .RemovableMedia = FALSE, + .MediaPresent = TRUE, + .LogicalPartition = FALSE, + .ReadOnly = FALSE, + .WriteCaching = FALSE, + .IoAlign = 4, + .LowestAlignedLba = 0, + .LogicalBlocksPerPhysicalBlock = 1, + }, + + .FvbProtocol = { + .GetAttributes = FvbGetAttributes, + .SetAttributes = FvbSetAttributes, + .GetPhysicalAddress = FvbGetPhysicalAddress, + .GetBlockSize = FvbGetBlockSize, + .Read = FvbRead, + .Write = FvbWrite, + .EraseBlocks = FvbEraseBlocks, + .ParentHandle = NULL, + }, + .ShadowBuffer = NULL, + .DevicePath = { + .Vendor = { + .Header = { + .Type = HARDWARE_DEVICE_PATH, + .SubType = HW_VENDOR_DP, + .Length = {(UINT8)sizeof (VENDOR_DEVICE_PATH), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) } + }, + .Guid = EFI_CALLER_ID_GUID, // GUID ... NEED TO BE FILLED + }, + .End = { + .Type = END_DEVICE_PATH_TYPE, + .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, + .Length = { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + } +}; + +/** + + Test If the Destination buffer sets (0->1) or clears (1->0) any bit in Source buffer ? + + @param[in] Source Source Buffer Pointer + @param[in] Destination Destination Buffer Pointer + @param[in] NumBytes Bytes to Compare + @param[in] Set True : Test Weather Destination buffer sets any bit in Source buffer ? + False : Test Weather Destination buffer clears any bit in Source buffer ? + + @retval TRUE Destination buffer sets/clear a bit in source buffer. + @retval FALSE Destination buffer doesn't sets/clear bit in source buffer. + +**/ +STATIC +BOOLEAN +TestBitSetClear ( + IN VOID *Source, + IN VOID *Destination, + IN UINTN NumBytes, + IN BOOLEAN Set + ) +{ + UINTN Index = 0; + VOID* Buffer; + + if (Set) { + Buffer = Destination; + } else { + Buffer = Source; + } + + while (Index < NumBytes) { + if ((NumBytes - Index) >= 8) { + if ((*((UINT64*)(Source+Index)) ^ *((UINT64*)(Destination+Index))) & *((UINT64*)(Buffer+Index))) { + return TRUE; + } + Index += 8; + } else if ((NumBytes - Index) >= 4) { + if ((*((UINT32*)(Source+Index)) ^ *((UINT32*)(Destination+Index))) & *((UINT32*)(Buffer+Index))) { + return TRUE; + } + Index += 4; + } else if ((NumBytes - Index) >= 2) { + if ((*((UINT16*)(Source+Index)) ^ *((UINT16*)(Destination+Index))) & *((UINT16*)(Buffer+Index))) { + return TRUE; + } + Index += 2; + } else if ((NumBytes - Index) >= 1) { + if ((*((UINT8*)(Source+Index)) ^ *((UINT8*)(Destination+Index))) & *((UINT8*)(Buffer+Index))) { + return TRUE; + } + Index += 1; + } + } + return FALSE; +} + +EFI_STATUS +NorFlashCreateInstance ( + IN UINTN NorFlashDeviceBase, + IN UINTN NorFlashRegionBase, + IN UINTN NorFlashSize, + IN UINT32 MediaId, + IN UINT32 BlockSize, + IN BOOLEAN SupportFvb, + OUT NOR_FLASH_INSTANCE** NorFlashInstance + ) +{ + EFI_STATUS Status; + NOR_FLASH_INSTANCE* Instance; + + ASSERT (NorFlashInstance != NULL); + + Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), + &mNorFlashInstanceTemplate); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + 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; + + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize); + if (Instance->ShadowBuffer == NULL) { + FreePool (Instance); + return EFI_OUT_OF_RESOURCES; + } + + if (SupportFvb) { + NorFlashFvbInitialize (Instance); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Instance->Handle, + &gEfiDevicePathProtocolGuid, + &Instance->DevicePath, + &gEfiBlockIoProtocolGuid, + &Instance->BlockIoProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + &Instance->FvbProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (Instance->ShadowBuffer); + FreePool (Instance); + return Status; + } + } else { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Instance->Handle, + &gEfiDevicePathProtocolGuid, + &Instance->DevicePath, + &gEfiBlockIoProtocolGuid, + &Instance->BlockIoProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (Instance->ShadowBuffer); + FreePool (Instance); + return Status; + } + } + + *NorFlashInstance = Instance; + + return Status; +} + +/* + Write a full or portion of a block. + It must not span block boundaries; that is, + Offset + NumBytes <= Instance->Media.BlockSize. + */ +EFI_STATUS +NorFlashWrite ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer +) +{ + EFI_STATUS Status; + UINTN BlockSize; + BOOLEAN DoErase; + VOID *Source; + UINTN SectorAddress; + + Status = EFI_SUCCESS; + Source = NULL; + + DEBUG ((DEBUG_BLKIO, + "%a(Parameters: Lba=%ld, Offset=0x%x, NumBytes=0x%x, Buffer @ 0x%08x)\n", + __FUNCTION__, Lba, Offset, *NumBytes, Buffer)); + + // The buffer must be valid + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Detect WriteDisabled state + if (Instance->Media.ReadOnly == TRUE) { + DEBUG ((DEBUG_ERROR, + "NorFlashWrite: 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; + + // We must have some bytes to write + if ((*NumBytes == 0) || (*NumBytes > BlockSize)) { + DEBUG ((DEBUG_ERROR, + "NorFlashWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", + Offset, *NumBytes, BlockSize )); + return EFI_BAD_BUFFER_SIZE; + } + + if (((Lba * BlockSize) + Offset + *NumBytes) > Instance->Size) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Write will exceed device size\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + // 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; + } + + SectorAddress = GET_NOR_BLOCK_ADDRESS ( + Instance->RegionBaseAddress, + Lba, + Instance->Media.BlockSize + ); + + // 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) { + Source = Instance->ShadowBuffer; + //First Read the data into shadow buffer from location where data is to be written + Status = NorFlashPlatformRead ( + Instance, + Lba, + Offset, + *NumBytes, + Source + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Failed to Read @ %p Status=%d\n", + __FUNCTION__, Offset + SectorAddress, Status)); + return Status; + } + // Check to see if we need to erase before programming the data into NorFlash. + // 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 = TestBitSetClear (Source, Buffer, *NumBytes, TRUE); + + // if we got here then write all the data. Otherwise do the + // Erase-Write cycle. + if (!DoErase) { + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + Offset, + NumBytes, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Failed to Write @ %p Status=%d\n", + __FUNCTION__, Offset + SectorAddress, Status)); + return Status; + } + return EFI_SUCCESS; + } + } + + // If we are not going to write full block, read block and then update bytes in it + if (*NumBytes != BlockSize) { + // Read NorFlash Flash data into shadow buffer + Status = NorFlashBlockIoReadBlocks ( + &(Instance->BlockIoProtocol), + Instance->Media.MediaId, + Lba, + BlockSize, + Instance->ShadowBuffer + ); + if (EFI_ERROR (Status)) { + // 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); + } + //Erase Block + Status = NorFlashPlatformEraseSector (Instance, SectorAddress); + if (EFI_ERROR (Status)) { + // Return one of the pre-approved error statuses + return EFI_DEVICE_ERROR; + } + if (*NumBytes != BlockSize) { + // Write the modified shadow buffer back to the NorFlash + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + 0, + &BlockSize, + Instance->ShadowBuffer + ); + } else { + // Write the Buffer to an entire block in NorFlash + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + 0, + &BlockSize, + Buffer + ); + } + if (EFI_ERROR (Status)) { + // Return one of the pre-approved error statuses + return EFI_DEVICE_ERROR; + } + + 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 +**/ +VOID +EFIAPI +NorFlashVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { + 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); + } + } + + return; +} + +EFI_STATUS +EFIAPI +NorFlashInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT32 Index; + NorFlashDescription* NorFlashDevices; + BOOLEAN ContainVariableStorage; + + ContainVariableStorage = 0; + + Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "%a : Failed to get Nor devices (0x%x)\n", + __FUNCTION__, Status)); + return Status; + } + + Status = NorFlashPlatformFlashGetAttributes (NorFlashDevices, mNorFlashDeviceCount); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a : Failed to get NOR device attributes (0x%x)\n", + __FUNCTION__, Status)); + ASSERT_EFI_ERROR (Status); // System becomes unusable if NOR flash is not detected + return Status; + } + + mNorFlashInstances = AllocateRuntimePool ( + sizeof (NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount); + if (mNorFlashInstances == NULL) { + DEBUG ((DEBUG_ERROR, "%a : Failed to allocate runtime memory \n")); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { + // Check if this NOR Flash device contain the variable storage region + ContainVariableStorage = + (NorFlashDevices[Index].RegionBaseAddress <= PcdGet64 (PcdFlashNvStorageVariableBase64)) && + ((PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize)) <= + (NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size)); + + Status = NorFlashCreateInstance ( + NorFlashDevices[Index].DeviceBaseAddress, + NorFlashDevices[Index].RegionBaseAddress, + NorFlashDevices[Index].Size, + Index, + NorFlashDevices[Index].BlockSize, + ContainVariableStorage, + &mNorFlashInstances[Index] + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a : Failed to create instance for NorFlash[%d] (0x%x)\n", + Index, Status)); + } + } + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + NorFlashVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mNorFlashVirtualAddrChangeEvent + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to create VirtualAddressChange event 0x%x\n", Status)); + } + + return Status; +} diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h new file mode 100644 index 0000000..3b1826c --- /dev/null +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h @@ -0,0 +1,146 @@ +/** @NorFlashDxe.h + + Copyright 2017 NXP + + 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 +#include + +#define GET_NOR_BLOCK_ADDRESS(BaseAddr,Lba,LbaSize) ( BaseAddr + (UINTN)((Lba) * LbaSize) ) + +#define NOR_FLASH_SIGNATURE SIGNATURE_32 ('n', 'o', 'r', '0') + +#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) + +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, + ... + ); + +// +// 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 +); + +EFI_STATUS +NorFlashWrite ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer +); + +#endif /* __NOR_FLASH_DXE_H__ */ diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf new file mode 100644 index 0000000..e83e813 --- /dev/null +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf @@ -0,0 +1,65 @@ +# @file +# +# Component description file for NorFlashDxe module +# +# Copyright 2017 NXP +# +# 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 = NorFlashDxe + FILE_GUID = 616fe8d8-f4aa-42e0-a393-b332bdb2d3c1 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = NorFlashInitialise + +[Sources.common] + NorFlashBlockIoDxe.c + NorFlashDxe.c + NorFlashFvbDxe.c + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/NXP/NxpQoriqLs.dec + +[LibraryClasses] + DxeServicesTableLib + HobLib + NorFlashLib + UefiDriverEntryPoint + UefiRuntimeLib + +[Guids] + gEfiSystemNvDataFvGuid + gEfiVariableGuid + gEfiAuthenticatedVariableGuid + gEfiEventVirtualAddressChangeGuid + gEdkiiNvVarStoreFormattedGuid ## PRODUCES ## PROTOCOL + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + +[Pcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gNxpQoriqLsTokenSpaceGuid.PcdIfcNandReservedSize + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c new file mode 100644 index 0000000..425fbce --- /dev/null +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c @@ -0,0 +1,816 @@ +/** @NorFlashFvbDxe.c + + Based on NorFlash implementation available in + ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 + +**/ +EFI_STATUS +InitializeFvAndVariableStoreHeaders ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + VOID* Headers; + UINTN HeadersLength; + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + + HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + sizeof (VARIABLE_STORE_HEADER); + Headers = AllocateZeroPool (HeadersLength); + if (Headers == NULL) { + DEBUG ((DEBUG_ERROR, "Memory allocation failed for Headers \n")); + return EFI_OUT_OF_RESOURCES; + } + + // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous. + ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize)) == PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize)) == PcdGet64 (PcdFlashNvStorageFtwSpareBase64)); + + // Check if the size of the area is at least one block size + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && (PcdGet32 (PcdFlashNvStorageVariableSize) / Instance->Media.BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / Instance->Media.BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / Instance->Media.BlockSize > 0)); + + // Ensure the Variable area Base Addresses are aligned on a block size boundaries + ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % Instance->Media.BlockSize) == 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % Instance->Media.BlockSize) == 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % Instance->Media.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_FVB_ATTRIBUTES_2) ( + EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped + EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1') + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled + ); + FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY); + FirmwareVolumeHeader->Revision = EFI_FVH_REVISION; + //i.e. if blocks are 0-5 then last block = 5, total blocks = 6 + 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 = (VARIABLE_STORE_HEADER*)((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*)mFlashNvStorageVariableBase; + + 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_ERROR, "%a: No Firmware Volume header present\n", __FUNCTION__)); + return EFI_NOT_FOUND; + } + + // Check the Firmware Volume Guid + if (CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) { + DEBUG ((DEBUG_ERROR, "%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_ERROR, "%a: FV checksum is invalid (Checksum:0x%X)\n", __FUNCTION__, Checksum)); + return EFI_NOT_FOUND; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength); + + // Check the Variable Store Guid + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) && + !CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)) { + DEBUG ((DEBUG_ERROR, "%a: Variable Store Guid non-compatible\n", __FUNCTION__)); + return EFI_NOT_FOUND; + } + + VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength; + if (VariableStoreHeader->Size != VariableStoreLength) { + DEBUG ((DEBUG_ERROR, "%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_FVB_ATTRIBUTES_2) ( + EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped + EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1') + ); + + // Check if it is write protected + if (Instance->Media.ReadOnly != TRUE) { + FlashFvbAttributes = FlashFvbAttributes | + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled + } + + *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 Indicates the 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. + Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER. + + @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 Indicates the 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 + ) +{ + *Address = mFlashNvStorageVariableBase; + 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 Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba Indicates the block for which to return the size. + + @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, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + Status = EFI_INVALID_PARAMETER; + } else { + // 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, "%a : *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", + __FUNCTION__, *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 Indicates the 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 + ) +{ + 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)); + + // 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. + while (Offset >= BlockSize) { + Offset -= BlockSize; + Lba++; + } + + if ((Instance->StartLba + Lba) > Instance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + return EFI_INVALID_PARAMETER; + } + + if ((Offset + *NumBytes) > BlockSize) { + *NumBytes = BlockSize-Offset; + } + + return NorFlashPlatformRead ( + Instance, + Instance->StartLba + Lba, + Offset, + *NumBytes, + Buffer + ); +} + +/** + 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 Indicates the 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; + UINTN BlockSize; + + Instance = INSTANCE_FROM_FVB_THIS (This); + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = Instance->Media.BlockSize; + + // The write must not span block boundaries. + while(Offset >= BlockSize) { + Offset -= BlockSize; + Lba++; + } + + if ((Instance->StartLba + Lba) > Instance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + return EFI_INVALID_PARAMETER; + } + + if ((Offset + *NumBytes) > BlockSize) { + *NumBytes = BlockSize-Offset; + } + + return NorFlashWrite ( + 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 Indicates the 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. + For example, the following indicates that two ranges of blocks + (5-7 and 10-11) are to be erased: + EraseBlocks (This, 5, 3, 10, 2, 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 == TRUE) { + // Firmware volume is in WriteDisabled state + DEBUG ((DEBUG_ERROR, "%a : 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, "%a : 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 = NorFlashPlatformEraseSector (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 +**/ +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")); + + mFlashNvStorageVariableBase = FixedPcdGet64 (PcdFlashNvStorageVariableBase64); + + // Set the index of the first LBA for the FVB + Instance->StartLba = (PcdGet64 (PcdFlashNvStorageVariableBase64) - 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; + + 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 + // + + // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory; + // even if we only use the small block region at the top of the NOR Flash. + // The reason is when the NOR Flash memory is set into program mode, the command + // is written as the base of the flash region (ie: Instance->DeviceBaseAddress) + RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size; + + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + Instance->DeviceBaseAddress, + RuntimeMmioRegionSize, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + ASSERT_EFI_ERROR (Status); + + Status = gDS->SetMemorySpaceAttributes ( + Instance->DeviceBaseAddress, + RuntimeMmioRegionSize, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + ASSERT_EFI_ERROR (Status); + + // + // The driver implementing the variable read service can now be dispatched; + // the varstore headers are in place. + // + Status = gBS->InstallProtocolInterface ( + &gImageHandle, + &gEdkiiNvVarStoreFormattedGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // 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; +} -- 1.9.1