From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.42.82; helo=nam03-by2-obe.outbound.protection.outlook.com; envelope-from=vabhav.sharma@nxp.com; receiver=edk2-devel@lists.01.org Received: from NAM03-BY2-obe.outbound.protection.outlook.com (mail-by2nam03on0082.outbound.protection.outlook.com [104.47.42.82]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 4540022183C83 for ; Fri, 1 Dec 2017 08:07:35 -0800 (PST) Received: from BLUPR0301CA0007.namprd03.prod.outlook.com (10.162.113.145) by CY1PR0301MB0729.namprd03.prod.outlook.com (10.160.159.147) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.260.4; Fri, 1 Dec 2017 16:11:59 +0000 Received: from BN1AFFO11FD022.protection.gbl (2a01:111:f400:7c10::157) by BLUPR0301CA0007.outlook.office365.com (2a01:111:e400:5259::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.282.5 via Frontend Transport; Fri, 1 Dec 2017 16:11:58 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=nxp.com; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1AFFO11FD022.mail.protection.outlook.com (10.58.52.82) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.20.239.4 via Frontend Transport; Fri, 1 Dec 2017 16:11:58 +0000 Received: from uefi-OptiPlex-790.ap.freescale.net ([10.232.132.56]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id vB1GBiuk003880; Fri, 1 Dec 2017 09:11:54 -0700 From: Vabhav To: , , , Date: Fri, 1 Dec 2017 09:40:05 +0530 Message-ID: <1512101406-11567-4-git-send-email-vabhav.sharma@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1512101406-11567-1-git-send-email-vabhav.sharma@nxp.com> References: <1512101406-11567-1-git-send-email-vabhav.sharma@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131566183184644144; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(336005)(7966004)(376002)(39860400002)(39380400002)(346002)(2980300002)(1110001)(1109001)(339900001)(199003)(189002)(97736004)(498600001)(189998001)(104016004)(54906003)(86362001)(47776003)(305945005)(51416003)(81166006)(77096006)(81156014)(356003)(2201001)(8676002)(316002)(5660300001)(85426001)(105606002)(6306002)(50466002)(15188155005)(53946003)(48376002)(16799955002)(8656006)(53936002)(33646002)(6666003)(50226002)(53376002)(16586007)(36756003)(8936002)(2906002)(110136005)(68736007)(106466001)(16200700003)(76176011)(2950100002)(4326008)(966005)(579004)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR0301MB0729; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD022; 1:E0nb/8vqYvsYUKNYpldZqz+AyZyP8kxOEkm6B8vwqHAK7ZNesoNxZlLGqIp20LmVAhOzUWq94v1YYchEadwuHTTT9U/VEcY17DnwBcE60PVWO918Obfa5NqyrBuoo46g MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ca8c2ae8-1928-4fac-56cf-08d538d63fa1 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(5600026)(4604075)(4534020)(4628075)(201703131517081)(2017052603286); SRVR:CY1PR0301MB0729; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0729; 3:Y+i4EKkSKreykCrRUv5N0IjyXzmMH7d3QmLTJpJ4WP1g51WLcijBwQgZY+5Fz4d/55vGF720LdDbvleGvhfHKqCFgJLQ0vQnenyjr94HRk6q7FNY2TxCrKnh28ePDgcAodx9o+6vPUCXGgqshjrqtnbrT3X9FChg33NIxQP9XjH09BYBoTrA/2lxL7+8wHp9R9zvzKiCSNKNEgd0KUSOR33J9jaDMC6WD7YB47BEVcZhxxxLOCzQCkMIvgL1ICAvTjzv4uocLGJ3in6tblsiOURfYG+qiDCfzdXddOYidlQSGjWx6Dy0zwpG+E3SZVFM19k9943N1DCsRw9DN9JLpgEkmhR8Djfx4V1L2c9OQBc=; 25:5zcH/HFfNqnBtRtnuFMS3NpznBH5S32nYVG9ilVyZaOMRNiCHm4S77+cjyXaaea69+62CnU9w7l9f0/+2FgPFz0bxhK6SZhfNfojgzQjOcQZTnOEMD9c76MCuxJPhHsTWRvhD+crsAnPEZxB7tQ+2YLQezzmt01WSgeHroNLUfgqDFxzdz+B/wyOdI69uN0P7+cxJs4F/tcoHl8rnWgv+YcZTDkLEzqVbT4LRMfR75Dd4emlLXaUNqY+tEYT9uVS4rwT6ZLqwCiuqM6pHNcOO5pd2D2x5PN89+8lhqBImE5WTlfwtmff+oe7f5BuuBfOOA2lAJD3MkKZrDO8B+aI6A== X-MS-TrafficTypeDiagnostic: CY1PR0301MB0729: X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0729; 31:t1l1nBigt1MVXlp96q7BYIjfM74v68t/6JeqRpxiYmqNOAQhplVmLP0pwGTaJ71bdC4pR5r8HsTLRSr00lJNI6yZByRn5Wah/0JYVE4WZq2fzR8RprVFncpXNJVkQPj8YU8TB302chAMsM6Fj4Bb7a6QJLWXoVJ99WY8DxRCdE76N1A2n2BxPOSRtV2e9O3ETGpSEE2bUjxiwWqiPnujDMiCVawOM5y6LR6Ma5sZzKE=; 4:DaJvf7EEA3ckeM00uBdIgd2hEXcw1HEdUAR+YY3bszgdH+QifdT5dBGkIxY1fLP5TpjGdXJ1VfdMvnhlFjZF9hD9PV2y6bWBfSM6zO7a6+g5fAhkWfjtW0IWaw0oeF+8zZ/DhSgOKKQgMqFD5cGru6Q00NxOaoig/dMLoJXgIzF15/jiADkI1AxDrUH0PL27jVL+hhMvq/YuCc9KPAtkGtl4xuGidUZcDir9SEOaP6Fshhh9f0KXyeF27s4vMObSsUUIlZHAAN5NMNHX88Xb948VBwxtuy9gKD+gaA3QuO/a9RDl6o0vWe9Xz1HfIUFmA255HGJ9NEJrgpxe23KJBjCPI4WymMUq09d6a1FWpiI= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(17755550239193); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6095135)(2401047)(8121501046)(5005006)(3231022)(3002001)(10201501046)(93006095)(93001095)(6055026)(6096035)(20161123559100)(20161123565025)(20161123561025)(20161123556025)(20161123563025)(201703131430075)(201703131433075)(201703131441075)(201703131448075)(201703161259150)(201708071742011); SRVR:CY1PR0301MB0729; BCL:0; PCL:0; RULEID:(100000803101)(100110400095)(400006); SRVR:CY1PR0301MB0729; X-Forefront-PRVS: 05087F0C24 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR0301MB0729; 23:ktZbuN5j61KSKHX3JvV3yukug31J87NyHgkH6/f?= =?us-ascii?Q?+3ehdrCIGS3TZhRGsDayEaqoL3ceQPbBuEm3ol4yuDQNHCs4dVvAXvuamfzr?= =?us-ascii?Q?OqsC2GCG2l+iIhJk2GoVjG3p5Ohn2EFaha6Lm+sIwwatQDqRWqrzDZwjTtnr?= =?us-ascii?Q?nNjXyNS5b+kopLsPIkkMxAQXJDo8M5a6hiCuFSgyPbZlO9bjMOotrJqFsKa0?= =?us-ascii?Q?QBHxxrjH9AekHByLjCYOB6miq7uruFUKL3sr6wccRP4z47EDEwOZQ1Sc3GZ+?= =?us-ascii?Q?5yIE9GmU9Qn9qpTlda6Hr6lJhrv8aq40i6Y8sp8r1TslKt83mDiqmOcF6iP+?= =?us-ascii?Q?RZPPTiBX/2jRX5UVNhpfUUDsyhZkr0DmIXijG04SG76JPrO2QpQserWnRdYi?= =?us-ascii?Q?gNKCaMC8TqSpIf4t1Q36Z/jRfWdI20pZb8l2WU83QwnGVByFYaBbjBd0bCXK?= =?us-ascii?Q?aeKNnvbpnDrEmu9BDbiEz9eMmHmweGiaSfrvvLErYjCGXQqrdKpvQMZxSP5D?= =?us-ascii?Q?eHhu4Qz/AqnkYVhcj81WJYNf8lU0VmeZPl1HBo2uWxEDG91Sd1fsXsYq4Rhf?= =?us-ascii?Q?K/LaEPdYDGv6KCJUuDWeDaRDKraQWtM/he3T2z//3mfm6opbcxEQWXJDwiyB?= =?us-ascii?Q?notQqMySJYz9OE9Xjj9uD3UbFljzIfUUvzLOZ27w/S9A4nkvKXxdjrfzzSeg?= =?us-ascii?Q?zOZ3iamy2V5E9U19AnF3nfx3Lf/8h4d607LA+8QGxNWPhai13qY+PruYw2w9?= =?us-ascii?Q?XrcTpfP5tFsW98to445fY7lNnpuTkfZPvUagzyizf7ZJK+tJPjId1D44EhpE?= =?us-ascii?Q?1bEnNmGYvZSarG7suVqD+CeCll8gHpAsGpS1zr+dNaD+PajX1B3cRlWhUYv3?= =?us-ascii?Q?ASh5SAZA5yijD4BU7RF+EFueAwMUXw/m2u3AnCF4UvEErR7rVayRIj3AXlj1?= =?us-ascii?Q?GuywKP05pQyUFIYIMATr7H+9hv105YsV3gxqq9aU9JDuioH4BQHYIox7F3Ld?= =?us-ascii?Q?FP4f9Vm1mV2PdALBhlvXC6MxWN7adMq2aKh+zNI9zZgd74b1xv/SPwW0gTTV?= =?us-ascii?Q?y+4Hp6BLQxqz1/nZhZ1D2NsNzZ+QF/S7DXYqdFUF/rX55U5RzDWnXX2GokLQ?= =?us-ascii?Q?OxgY+4Jb5J3WYtCHIkqKkvb86xXkniW1R3wAM5iCc2pOkXfSAmYLewwlmSWn?= =?us-ascii?Q?LRgkE0z6DgEwksGZZqkgTgjYUD+nCIlM/Qjr1oN9AFH6ZCSjnCT976J9xBJw?= =?us-ascii?Q?ka5bb1pj5YCMyUt2m2z9pGb5cuCccin2ceERqJ+jvpOchkRo+P1o+5jogQvD?= =?us-ascii?Q?J9+3V8cjPli7STP1pynwIkpXGmvcUufWBHcYGZiVgPHfC?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0729; 6:JjedwCl6zdZfgdp8Y7eWNu8mPN9NtTSl7hBOm12js+D73yEomWxidyqVA1MOwXOLh8+KnRzgo4JgF3T59z3L/NsjyVa01wCfI3JP6Ot2z9Ru+YRL+t8zcHp96OPYVEHi/kYuqr5RiqJez3oIyMenIUyIGewmhTmDPE1yLAn0Xiqf4s9Gct7qor9pWeQ3DpqW70S4WjYYzmywqhRrFYveT3pV9931KFnCJz0fxo4z/XLZRzUj7RqpRa45pVuD1YBn/LedidvFD5KgVQBJG/29gCIGmfmdOyYhjiqyaDIOGm0W7DNKQ4Jsu0xLf9dkByC6WRJDm+ffYvZardx1nxenwLjvG3PmeZImR0lgXaLPVxo=; 5:Q1C4GnkRb1zMmJrldkVw5ZgMPa1S1Pu/AwC4MJ7pqKx4Qd0xQR9floTITG4zXGxfUjFiC2kVBAqDCLuKq05LLxpHROnl/x43riceN7D0zLSvzK5o8NxO1O/57NHQjxI8b4mM1nZ8C0LHVhQuEys4jd9fCHz691EPeITfoYO6zCE=; 24:U23pLLVZkzy7qoiEHnzzJ5GFvjw1ZQcoWMDoLGxkp/CoRknyuD5iq/P8NWn2KQKyBC8RcKavVU2Riu9QvhsfzSDK4797OKYPfzyierJLsuU=; 7:uW3Ixq1xwWxWvjqmYSpchzttYl+EDhJRLPYLLruJMLai6HIQOMeG2fL7fFoqf9kO/AWrluTc/w19TLKFL4h/zxetWKnMqfjXjR/dnNtNh8mLfG8JMMz7i06rWplzuD3vWSoiPatPgRlYrKtLUZXp/EFREFSbK+fE3ItxDqqtlwnVLihFv0CSwbff3NzCn9P2z1nEXNupkWX4y8VdxJ2zzbX884DVgtckD+5VeXhroJuN77QOAYTf6F7FNc3aq4sB SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Dec 2017 16:11:58.1836 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ca8c2ae8-1928-4fac-56cf-08d538d63fa1 X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR0301MB0729 Subject: [PATCH 3/4] Platform/NXP : Add Support for NOR Flash driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Dec 2017 16:07:35 -0000 Content-Type: text/plain This patch adds support for NOR flash Driver Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Vabhav --- .../NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c | 254 +++++++ Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c | 446 ++++++++++++ Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf | 65 ++ Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 807 +++++++++++++++++++++ Platform/NXP/Include/Library/NorFlash.h | 222 ++++++ 5 files changed, 1794 insertions(+) create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c create mode 100755 Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c create mode 100644 Platform/NXP/Include/Library/NorFlash.h diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c new file mode 100644 index 0000000..5f3c2ad --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c @@ -0,0 +1,254 @@ +/** @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 + +// +// 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 *pReadBuffer; + 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 ; + + 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) { + Status = EFI_INVALID_PARAMETER; + } + else if (!Media->MediaPresent) { + Status = EFI_NO_MEDIA; + } + else if (Media->MediaId != MediaId) { + Status = EFI_MEDIA_CHANGED; + } + else if ((Media->IoAlign >= 2) && + (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + } + else 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)); + 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 { + 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 *pReadBuffer */ + pReadBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Read data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, + pReadBuffer = pReadBuffer + BlockSizeInBytes) { + DEBUG((DEBUG_BLKIO, "%a: Reading block #%d\n", + __FUNCTION__,(UINTN)CurrentBlock)); + + Status = NorFlashPlatformRead (Instance, CurrentBlock, (UINTN)0 , + BlockSizeInBytes,pReadBuffer); + if (EFI_ERROR(Status)) { + break; + } + } + } + DEBUG((DEBUG_BLKIO,"%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); + + 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 *pWriteBuffer; + + 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 ; + + 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; + } + else if (Media->MediaId != MediaId) { + 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 { + BlockSizeInBytes = Instance->Media.BlockSize; + + pWriteBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Program data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; + BlockCount++, CurrentBlock++, + pWriteBuffer = (pWriteBuffer + BlockSizeInBytes)) { + 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, pWriteBuffer); + if (EFI_ERROR(Status)) { + break; + } + } + } + DEBUG((DEBUG_BLKIO, "%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); + 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/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c new file mode 100644 index 0000000..1d553fc --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c @@ -0,0 +1,446 @@ +/** @file NorFlashDxe.c + + 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 + +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; + + 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, + &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; + + IfcNorInit(); + + 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/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf new file mode 100755 index 0000000..2da8a51 --- /dev/null +++ b/Platform/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] + NorFlashDxe.c + NorFlashFvbDxe.c + NorFlashBlockIoDxe.c + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + Platform/NXP/NxpQoriqLs.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.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 + +[Depex] + # + # NorFlashDxe must be loaded before VariableRuntimeDxe in case empty flash needs populating with default values + # + BEFORE gVariableRuntimeDxeFileGuid diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c new file mode 100644 index 0000000..e368464 --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c @@ -0,0 +1,807 @@ +/*@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 + +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; +} diff --git a/Platform/NXP/Include/Library/NorFlash.h b/Platform/NXP/Include/Library/NorFlash.h new file mode 100644 index 0000000..79312f5 --- /dev/null +++ b/Platform/NXP/Include/Library/NorFlash.h @@ -0,0 +1,222 @@ +/** @NorFlash.h + + Based on NOR flash access APIs used in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.h + + 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. + +**/ + +#ifndef __NOR_FLASH_H__ +#define __NOR_FLASH_H__ + +#include +#include + +#define NOR_FLASH_ERASE_RETRY 10 + +#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) + +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE; + +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (NOR_FLASH_INSTANCE* Instance); + +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL End; +} NOR_FLASH_DEVICE_PATH; + +struct _NOR_FLASH_INSTANCE { + UINT32 Signature; + EFI_HANDLE Handle; + BOOLEAN Initialized; + NOR_FLASH_INITIALIZE Initialize; + UINTN DeviceBaseAddress; + UINTN RegionBaseAddress; + UINTN Size; + EFI_LBA StartLba; + EFI_BLOCK_IO_PROTOCOL BlockIoProtocol; + EFI_BLOCK_IO_MEDIA Media; + BOOLEAN SupportFvb; + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; + VOID* ShadowBuffer; + NOR_FLASH_DEVICE_PATH DevicePath; +}; + +// +// NorFlashLib.c related +// + +EFI_STATUS +NorFlashPlatformWriteBuffer ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +NorFlashPlatformEraseSector ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN SectorAddress + ); + +EFI_STATUS +NorFlashPlatformControllerInitialization ( + VOID + ); + +EFI_STATUS +NorFlashPlatformRead ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN BufferSizeInBytes, + OUT UINT8 *Buffer + ); + +EFI_STATUS +NorFlashPlatformReset ( + IN UINTN Instance + ); + +extern CONST EFI_GUID* CONST mNorFlashVariableGuid; + +// +// NorFlashFvbDxe.c +// + +EFI_STATUS +EFIAPI +NorFlashFvbInitialize ( + IN NOR_FLASH_INSTANCE* Instance + ); + +EFI_STATUS +EFIAPI +FvbGetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbSetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbGetBlockSize( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ); + +EFI_STATUS +EFIAPI +FvbRead( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbWrite( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbEraseBlocks( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ); +// +// NorFlashBlockIoDxe.c +// + +// +// 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__ */ -- 1.9.1