From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:400c:c0c::233; helo=mail-wr0-x233.google.com; envelope-from=leif.lindholm@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-wr0-x233.google.com (mail-wr0-x233.google.com [IPv6:2a00:1450:400c:c0c::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 5E0E82265A164 for ; Tue, 17 Apr 2018 09:23:41 -0700 (PDT) Received: by mail-wr0-x233.google.com with SMTP id o15so6187342wro.11 for ; Tue, 17 Apr 2018 09:23:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=fs7FMTkxmXKeyiPgwNYdAQDk8lHT6q7MCQJ53qfqagc=; b=VzqH0lejqBIq8nfji1LaJd00xVRz3YBM3ktFIIohjzbE/541Xjy5ct7v2w3S+TSZ+t KrH3VIUZ4uEEdoPrW6ebVgcMLp1rn7xqSswSD5tDXJIaFCxplPUvTUmuLtrBJ/vHwu2F 7NkX0n8Uh8Ok28jc6b0PR305hV+ejzxe3HJiA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=fs7FMTkxmXKeyiPgwNYdAQDk8lHT6q7MCQJ53qfqagc=; b=Y7rOlbl8cfwt4QYByNyKCXfJYHaQm5XGllakoEIZMtvD/GsONI10jLkOIY0DdAeWGk ZLpCvLUNZE7YSFuVrG0TuiYmcFWoVlDYrYBHu5KUdc8yYWKG6mFqIVqMb79nEGi7l6DF t8tAvb6+G31SELGeSPbjTqrsrLMyW1bNlebiP6t+YIAOHnQ8dzW6ROBQs59dugBdhBRI fd1AMkMd+owJ6jpZTO7HEsf+0hQh6NY2uwkrgclQJ54R8aIupT/gar8eXTaLr5N2IpuS y9HletcX/y9dA5tXP8zOgkE7HyqJxZxnNM01otnrxbpTx7+yXyJQT/nJIc7HJoQoDBiw MaUw== X-Gm-Message-State: ALQs6tA2dsTrCkDfPAXNAhxjJHlL2T0z6unWsmgRf6Y9TW9p54Pi3g/7 i/c/CbE7b++pCYZQIOYR8w+6eg== X-Google-Smtp-Source: AIpwx4/+9ompJPeATd7rm3Lue5NIE+ZYxpePntG0gBALBZWHM2EbgHx2FypQpu/iIletmCI07fE0jw== X-Received: by 10.223.136.163 with SMTP id f32mr2110322wrf.199.1523982218622; Tue, 17 Apr 2018 09:23:38 -0700 (PDT) Received: from bivouac.eciton.net (bivouac.eciton.net. [2a00:1098:0:86:1000:23:0:2]) by smtp.gmail.com with ESMTPSA id v13sm13580552wrf.90.2018.04.17.09.23.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 17 Apr 2018 09:23:36 -0700 (PDT) Date: Tue, 17 Apr 2018 17:23:35 +0100 From: Leif Lindholm To: Meenakshi Cc: ard.biesheuvel@linaro.org, edk2-devel@lists.01.org, udit.kumar@nxp.com, v.sethi@nxp.com Message-ID: <20180417162335.pifcttbbojaaho2o@bivouac.eciton.net> References: <1518771035-6733-1-git-send-email-meenakshi.aggarwal@nxp.com> <1518771035-6733-17-git-send-email-meenakshi.aggarwal@nxp.com> MIME-Version: 1.0 In-Reply-To: <1518771035-6733-17-git-send-email-meenakshi.aggarwal@nxp.com> User-Agent: NeoMutt/20170113 (1.7.2) Subject: Re: [PATCH edk2-platforms 16/39] Silicon/NXP : Add NOR driver. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Apr 2018 16:23:42 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline (Responding somewhat out of sequence, as I'm going through to build this port and encountering issues.) This patch will require something similar to edk2-platforms 79c9dd55a32752b7ae11d5f1a50fa3ae27d6d126 in order to work with recent upstream edk2. (gVariableRuntimeDxeFileGuid has gone away with edk2 6281a2ed3bb3ffe57ed54cabd9a31dcf13b415f8.) (Further comments inline below.) On Fri, Feb 16, 2018 at 02:20:12PM +0530, Meenakshi wrote: > From: Meenakshi Aggarwal > > 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 | 258 +++++++ > Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c | 438 +++++++++++ > Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.h | 146 ++++ > Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf | 66 ++ > Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 805 +++++++++++++++++++++ > 6 files changed, 1811 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..efa2197 > --- /dev/null > +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c > @@ -0,0 +1,258 @@ > +/** @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 = ((UINTN)BufferSizeInBytes) / Instance->Media.BlockSize ; BufferSizeInBytes is already UINTN, why the cast? > + > + DEBUG ((DEBUG_BLKIO, "%a : (MediaId=0x%x, Lba=%ld, " > + "BufferSize=0x%x bytes (%d kB)" > + ", BufferPtr @ 0x%p)\n", > + __FUNCTION__,MediaId, Lba, > + BufferSizeInBytes, Buffer)); Please don't break output string: I'm happy to take either DEBUG ((DEBUG_BLKIO, "%a : (MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%p)\n", __FUNCTION__,MediaId, Lba, BufferSizeInBytes, Buffer)); or two calls to DEBUG on separate lines. > + > + if (!Media) { > + Status = EFI_INVALID_PARAMETER; > + } > + else if (!Media->MediaPresent) { > + Status = EFI_NO_MEDIA; > + } > + else if (Media->MediaId != MediaId) { > + Status = EFI_MEDIA_CHANGED; > + } This is a lot of tests where most of them just set a return value. The compiler will take care of any optimisation required - just return directly and skip all these elses. But, when using elses elsewhere, please put them on same line as }. > + else if ((Media->IoAlign >= 2) && > + (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { Please indent continuation to reflect it's inside the if test. else if ((Media->IoAlign >= 2) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { (Well, if you drop the else as per above, this fits in 80 columns.) > + Status = EFI_INVALID_PARAMETER; > + } > + else if (BufferSizeInBytes == 0) { > + // Return if we have not any byte to read > + Status = EFI_SUCCESS; > + } > + else 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)); Indentation. (Please adjust throughout.) > + Status = EFI_INVALID_PARAMETER; > + } else 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)); > + Status = EFI_INVALID_PARAMETER; > + } else { And just make this the remainder of the function. > + 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++, CurrentBlock++, > + ReadBuffer = ReadBuffer + BlockSizeInBytes) { Could you reformat this as for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++) { ... CurrentBlock++; ReadBuffer = ReadBuffer + BlockSizeInBytes; } ? > + DEBUG ((DEBUG_BLKIO, "%a: Reading block #%d\n", > + __FUNCTION__,(UINTN)CurrentBlock)); Missing space after ','. > + > + Status = NorFlashPlatformRead (Instance, CurrentBlock, (UINTN)0 , Does that 0 need a (UINTN)? Trailing space after 0. > + BlockSizeInBytes,ReadBuffer); > + if (EFI_ERROR (Status)) { > + break; > + } > + } > + } > + DEBUG ((DEBUG_BLKIO,"%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); And move this DEBUG to call sites if needed. > + > + 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 = ((UINTN)BufferSizeInBytes) / Instance->Media.BlockSize ; BufferSizeInBytes is already UINTN. > + > + 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) { > + Status = EFI_NO_MEDIA; Return directly. > + } > + else if (Media->MediaId != MediaId) { No else (throughout). > + Status = EFI_MEDIA_CHANGED; > + } > + else if (Media->ReadOnly) { > + Status = EFI_WRITE_PROTECTED; > + } > + else if (BufferSizeInBytes == 0) { > + Status = EFI_BAD_BUFFER_SIZE; > + } > + else 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)); > + Status = EFI_INVALID_PARAMETER; > + } else 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)); > + Status = EFI_INVALID_PARAMETER; > + } else { Remainder of function. > + BlockSizeInBytes = Instance->Media.BlockSize; > + > + WriteBuffer = (UINT8 *)Buffer; > + > + CurrentBlock = Lba; > + // Program data block by Block > + for (BlockCount = 0; BlockCount < NumBlocks; > + BlockCount++, CurrentBlock++, > + WriteBuffer = (WriteBuffer + BlockSizeInBytes)) { Same comment for for-loop layout: can you keep only the BlockCount update in the for statement and move the other updates to end of loop body? > + 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; > + } > + } > + } > + DEBUG ((DEBUG_BLKIO, "%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); DEBUG at call site if needed. > + 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..0e7703c > --- /dev/null > +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.c > @@ -0,0 +1,438 @@ > +/** @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 "NorFlashDxe.h" > + > +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; > + > +// > +// Global variable declarations > +// > +NOR_FLASH_INSTANCE **mNorFlashInstances; > +UINT32 mNorFlashDeviceCount; > + > +NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { > + .Signature = NOR_FLASH_SIGNATURE, > + .Initialized = FALSE, > + .Initialize = NULL, > + .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 } > + } > + } > +}; > + > +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; Spaces around '-'. > + > + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize); > + if (Instance->ShadowBuffer == NULL) { > + FreePool (Instance); > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (SupportFvb) { > + Instance->SupportFvb = TRUE; > + Instance->Initialize = NorFlashFvbInitialize; > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Instance->Handle, Indent to two spaces from start of function name: 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 { > + Instance->Initialized = TRUE; > + > + 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..24504f2 > --- /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..4081619 > --- /dev/null > +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf > @@ -0,0 +1,66 @@ > +# @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] > + NorFlashDxe.c > + NorFlashFvbDxe.c > + NorFlashBlockIoDxe.c > + > +[Packages] > + ArmPlatformPkg/ArmPlatformPkg.dec > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + Silicon/NXP/NxpQoriqLs.dec > + > +[LibraryClasses] > + DxeServicesTableLib > + HobLib > + NorFlashLib > + UefiDriverEntryPoint > + UefiRuntimeLib > + > +[Guids] > + gEfiSystemNvDataFvGuid > + gEfiVariableGuid > + gEfiAuthenticatedVariableGuid > + gEfiEventVirtualAddressChangeGuid > + > +[Protocols] > + gEfiBlockIoProtocolGuid > + gEfiFirmwareVolumeBlockProtocolGuid > + > +[Pcd.common] > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize > + gNxpQoriqLsTokenSpaceGuid.PcdIfcNandReservedSize > + > +[Depex] > + # > + # NorFlashDxe must be loaded before VariableRuntimeDxe in case empty flash needs populating with default values > + # > + BEFORE gVariableRuntimeDxeFileGuid (This one disappeared.) / Leif > diff --git a/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c > new file mode 100644 > index 0000000..378546d > --- /dev/null > +++ b/Silicon/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c > @@ -0,0 +1,805 @@ > +/** @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 "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; > + > + 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); > + 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)); > + > + if (!Instance->Initialized && Instance->Initialize) { > + Instance->Initialize(Instance); > + } > + > + // 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; > + > + if (!Instance->Initialized && Instance->Initialize) { > + Instance->Initialize(Instance); > + } > + > + // 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")); > + > + Instance->Initialized = TRUE; > + 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); > + > + // > + // 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 >