From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=40.107.0.84; helo=eur02-am5-obe.outbound.protection.outlook.com; envelope-from=meenakshi.aggarwal@nxp.com; receiver=edk2-devel@lists.01.org Received: from EUR02-AM5-obe.outbound.protection.outlook.com (mail-eopbgr00084.outbound.protection.outlook.com [40.107.0.84]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 444EE223230E1 for ; Fri, 16 Feb 2018 00:47:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=NZUSZXqSsMOAeSreB41Q64Tn1kDrRakyDaN7KwYmkrg=; b=LntTNBW0sYD26wlaiPTKciOd5ec/9cHdW3Yg1G/+yWTwtVMQTVwnRTqL0Bd0SJH3jYGT71RgRy8zgE6/OIKyLHPstb6NBB2Kk2J5rlOO+ERDTcGBU/2aQhKZLoD01ZOpac3kjvH+LY43cyw+3v5O9KOKEEBzY8m+fWpICkUnFCM= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=meenakshi.aggarwal@nxp.com; Received: from idcbfarm.ap.freescale.net (192.88.169.1) by VI1PR04MB1008.eurprd04.prod.outlook.com (2a01:111:e400:5090::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.485.10; Fri, 16 Feb 2018 08:53:36 +0000 From: Meenakshi To: ard.biesheuvel@linaro.org, leif.lindholm@linaro.org, michael.d.kinney@intel.com, edk2-devel@lists.01.org Date: Fri, 16 Feb 2018 14:20:12 +0530 Message-Id: <1518771035-6733-17-git-send-email-meenakshi.aggarwal@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1518771035-6733-1-git-send-email-meenakshi.aggarwal@nxp.com> References: <1518771035-6733-1-git-send-email-meenakshi.aggarwal@nxp.com> MIME-Version: 1.0 X-Originating-IP: [192.88.169.1] X-ClientProxiedBy: HK2PR02CA0172.apcprd02.prod.outlook.com (2603:1096:201:1f::32) To VI1PR04MB1008.eurprd04.prod.outlook.com (2a01:111:e400:5090::28) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-MS-Office365-Filtering-Correlation-Id: ec675015-9a60-4c42-bc4c-08d5751ac648 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(48565401081)(5600026)(4604075)(4534165)(4627221)(201703031133081)(201702281549075)(2017052603307)(7153060)(7193020); SRVR:VI1PR04MB1008; X-Microsoft-Exchange-Diagnostics: 1; VI1PR04MB1008; 3:qnyR4AOkxnsg/7PKYFQ3OQlZ+MeNWYnEGMB48+7gRMPa+Dq+itlJKZQ7p/FtlwqYlUkighIL8cuog1ysS5ZwfBGmjahbtQxiRq+NSpCqh5Snd2Z1x6tdcrWAmzYFtxlaZ7d8w2bD45wDVKpN8fqlN6lMwYVaGr+xCFmGlrB7d1bAOYDh+AKtVm34PyD4Z3KzsKFRReoqMA4ADBp8SfQrU5bj95W4CVxbXgGQVNS3UTo7zRS9ooyZT9M5F5v0rJOr; 25:J3VFE9V3ibQCHtCPlSMHFyUhajtTtvT4VpxHeU7/BjueV4PuYfoY2c5hIzYjSXh7WCofss6jpuv96dDFVOhsvckEkReji0cGGG6jgEYco8KuQX33XvKnleRtgKY6wntOh1UflPMuJYfTqyZ0c0PO/tNj3kREziy0s16cHeiz56wpvsZZl8b/7g8bZysMYuL0yKXn+wm0XdpAOB3B8n5bU/srrBlai35cX0y/mVAfQoqYkFHgqcYWXfjfVvaGy0hJoRyKolTnunvm7wQwsXssBlE0bZqBWiLO8h2g4v4K8cHL0t9viseQ6bkqBSJ+lf9YmSf4Kci/woO13MKZrfgDTw==; 31:gKwZjXguWAHtTnfs7abG1IEHDq7KcT+CmlixXNX70S3xP6MQWPygnl5KUkRN9NmaExtc1ysH57fLgSB00W9/yUs+snoRxuBKN8kCPOy74tujTb4iUJOokfEbsv1RBAI7a1DifqpIAQRe3OV4CcUkkt4epl8C2jhWhCeAnP74lSlLpnupmaSQeiXNc7gRZ21Otst3qKuQGmgUgHg3jP1TeDlpuEhod4ZACg2DHCV3i2U= X-MS-TrafficTypeDiagnostic: VI1PR04MB1008: X-Microsoft-Exchange-Diagnostics: 1; VI1PR04MB1008; 20:pHEPmo/vgYpSyOXQNAW6CeQCZvtIFSo41LcrnaFxyYUTZy0Xh9TPx2bXUwm6BChC7Nw22o/VZyH84ouaa+XSnCdhTxHCqgpZe23osI39kejK7KX6IYHA8s0gzJd7EMfqazdOsDdkeOIOhzA29UX6hVLjVkNTWY2KizuE+bJKGdo2uo8l10hr2NMq6RCcFw3Afq/+bDb0AsmLNKOsGjYY99br5TJUbsA0dQIqj80E6tIv5yb6vlJ+VTAY++TyYdxU6zAYV9wnIyEHCvKCKzvpjiTk8/CBGlCae0335+qYJhtrL2uIZ+p08LOqrEstXJV0mMHcIMaO8NeHd2TFcVKlhhqVLBbUGL8khLsHGsDwG2yliAJ9aJF1C9vsxovvtLm21HkPigfk4S33D0jBh9MSDC24LAEF1If9E8OZt/E1ClFSVBS8yp13SpOyDveLIUhUH3XVFE8tO5jp3J/O6voBFQhwGftTL0cMh//mpIRTOcnrGYn4M1I9QUGcDWyi1GAx; 4:6oz3jZWsFqfJjrHx+ccwtxLDILfRQX0FOEQhyHwBz9Tin/GqZ+STzikZN82NoMK+vLp+K2Xtt3UyTu/PWX8DoPoH+/oVlTT91SJyESIgMyGSTKyF7Iy7CAjOIVKAFYJXnYDhWEDe6DGN/03CmQA6GyvO23JfwXY9T9JUn45cwXhJIvFC6HyrFB3Ip4ljBsEu5X1OSoBEiL4gIglTvS+kuhGOJyaqBzJ+tAJsKgnKpV4lxvR8Tf136LIiVsKvZjqva6PoTvd92Ny1JBPyKFEr0oXCfQ0rZU9rzugC3MBRYGJB55QIq0n5r664t5dPSfPUBw5LEdAUWvMdmO2QEYyO+wRHfTjTQ3vSNyeTr/AlteM= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(17755550239193); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040501)(2401047)(8121501046)(5005006)(93006095)(93001095)(10201501046)(3002001)(3231101)(944501161)(6055026)(6041288)(20161123558120)(20161123564045)(20161123560045)(20161123562045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011); SRVR:VI1PR04MB1008; BCL:0; PCL:0; RULEID:; SRVR:VI1PR04MB1008; X-Forefront-PRVS: 0585417D7B X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(346002)(376002)(39380400002)(396003)(39860400002)(366004)(199004)(189003)(86362001)(575784001)(6486002)(8676002)(76176011)(36756003)(53376002)(966005)(4326008)(6116002)(15188155005)(16799955002)(7736002)(386003)(68736007)(186003)(26005)(53936002)(305945005)(16526019)(81156014)(3846002)(114624004)(6506007)(478600001)(50226002)(16586007)(8936002)(2950100002)(316002)(2906002)(59450400001)(25786009)(97736004)(50466002)(48376002)(105586002)(52116002)(47776003)(81166006)(51416003)(53946003)(5660300001)(6666003)(106356001)(66066001)(16200700003)(6306002)(6512007)(559001)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR04MB1008; H:idcbfarm.ap.freescale.net; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: nxp.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR04MB1008; 23:5eHnVQFZnpkJiDfQeCAQh8mhVWGQcJrLObkGzMk0z?= =?us-ascii?Q?suk7ezKJbVNzmq4ITpgmCw6G7cqPLqYMrD8mhz6bdPICrkWEjPwBfA1h66nf?= =?us-ascii?Q?Pu3Tyjuo0QcidxzDO0ryyx6iTkUPcvWTurMeXLP6SNqEGdyVsYf4UmlXYr3P?= =?us-ascii?Q?/cLnBJETn5+S7GPdohLoyuHXWVSUDqaqa46jPFCFDJa92bLEzWI3xlPyZzEX?= =?us-ascii?Q?9U2TK5QDB4EpR9aiLhI4bpOKlCl8rwx45AXbokCRwMQTwRsByVwxzvrI5Cee?= =?us-ascii?Q?FHCD5evmfv9xfi6QEvZYIALAmYco91x2IairZSlezw/fnYy2JHu7Sgg3mC7r?= =?us-ascii?Q?ZAd0ElTz7gfCRSYIDT1Ut7DLobqILJG6JTzotR50vqWF3XKS6sH6GVGK/zt6?= =?us-ascii?Q?5lQX1cAXkVwgg5jmWTQUSwUVPHwLzfNeU4yS8l5CL3SqdIl6p9A3VwRNodxO?= =?us-ascii?Q?iJE5MkuhK6Svu2kPz/Sf9kVdWlYDj6XeUhUXr2BNw7K46SqzJR7CXaxi/t6V?= =?us-ascii?Q?m8q/cDaavk1eJU6WYdnJTQcbKqavhd7JNe9/PpwqzSU3Sur8wnEa5+Ej3cIS?= =?us-ascii?Q?XRUNTJHRPNh4d48g9V5FF9ZRsMX+C87geZTy6s32/R8elymue/E+hoKLksDq?= =?us-ascii?Q?G2ORzfgkg5sq6rnCn3WjQHgmyqQto9js7EZC2QX9pjCuhLJK6aW2x/+suQ2X?= =?us-ascii?Q?zM98ymme5pA4v0j9gLKl5SYdXzXTlh69FtBKkP4IfrNpdZEt4KAjRVauQBjV?= =?us-ascii?Q?3DTx5EsSGB+C5biglue0yQ3yHR0l2kXG4IfM3hxlTtJkioS3yfTeyPcephSU?= =?us-ascii?Q?8F7oL/Zi8OQS9FXOdzaKLnkkSnpJiMd/XoryzU4FfEdWOzblHW7azkSdCpsG?= =?us-ascii?Q?ZQzI8C6Yh6pnEzvL3qCuCJhkL/xwD81Li1uexaVWQksyL/dVCfaugtKPTgtC?= =?us-ascii?Q?Qhoh3P6E7g12kjJ42TDU0BaL8gbRiFfPeingEqyZ4ugFTkdbjPVrgYHF+3A4?= =?us-ascii?Q?ZUoLHSa6A7TWfYzWHQEth0nA5dTrCEHP+t7lSAyOEuf7JZUmlyb4Tbxrt6qw?= =?us-ascii?Q?3BtVBu8i7fQAb1ENcy3JLBkopqOzWo+aY2IwY+Ubt7rHTKOpW0qZGtTskmtN?= =?us-ascii?Q?Dj5jvC495fp5WD9aEHR/1bhkM6KoB3TnAn/ex3DM4sZkXRh5KOj/0yXXrFtc?= =?us-ascii?Q?OGBUFqWypeKWzdz0Krqeve6UKN91OppFdRexA9tJ5TiKVWf7E1HucwGivTrR?= =?us-ascii?Q?HP4bQv+BXcg8qmaLh59c8PPaCYBCT4sWPBwweYD/qwmsv7+uaHniOazCRS82?= =?us-ascii?Q?Gx/De5bBcDAdq9mY7XSR/V+WsRbOL9/AvtbKevvSDsy?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR04MB1008; 6:TlpysI/4AxXYCczLsXQCinHKsWVt2Ng+JMyAVm8QRsIoiUbaXGUQZTZLYg4jS2QefEgi5KSdkSMte9ZPc7hkkD+lGS0EyS8lNGXQMmUV4sM+GN8VoK+jJ4GxYZCggUdSbIYlOhAH5BJENwrRBVkS44t7qiRNhAXyNuzy0XuU5xc++xv0+U7F6qKZaZtdyZ3HgpUUWOnN3MEg249CLGJnKnftKCn7TJ15woOk1n0ATFWJZt7iDgRjuLiEuOoEkXCxcWBQS9P19rDX/htLblnfpn3VfvTMih70vGnpJbU/tRpHwJFOEIskG6RAaCbi09333cHZXgRULaPnrRCkFLXJJDTyaIJSfq2LRmO+ejJBXrU=; 5:PgH9kOPDEy9TjcC9lxNWqd5yqQiKGURp2gdyCcmZmkh9aVPLe8Gpu1MyH4Q3Qwf4PXYHeAIx+xn4VmEc+kXSgKNwQJ6JIo5WXB6Mjd3PPv2M1OgOmteMNdNWMHa6G23QiNM9+a3jte0lBGQfHID/HUqpGpU9/gC7ouSWfshxDVo=; 24:En9zpG+Son+ocsYTBpnK0M/ZmQhLmoxPUH7Z9cTkU36EqYwtJnYBkroPVuSRuuaQwYlCncI/ASJYbBd+4HE8VUGxBRNLOQnHU15r+kCQvyY=; 7:nrlxrbSI4zXvXsWIRll32GXM3LQlf/3HboVgY7ArcPEc3KoH4Sei+qCessdwmYy6iamf0xADuXiKcQeNOsxfpKBqFd1aH20XRCuuK9NCZFxRuSvIvhRiQOJ8lMphtKc9qziJjCg55EN4WSJZQ5i/QH+vRsDrenS+yGjrkE1CE/W2G2ykPbhxtEAOWj+yg/Ds5z6VYlji497v6f57V54umP6UhS2KIRuVTkewoqQbe1uYusmEIH2Y0Vqzr6MHTwxH SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Feb 2018 08:53:36.9517 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ec675015-9a60-4c42-bc4c-08d5751ac648 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB1008 Subject: [PATCH edk2-platforms 16/39] Silicon/NXP : Add NOR driver. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Feb 2018 08:47:51 -0000 Content-Type: text/plain 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 ; + + 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 *ReadBuffer */ + ReadBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Read data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, + ReadBuffer = ReadBuffer + BlockSizeInBytes) { + DEBUG ((DEBUG_BLKIO, "%a: Reading block #%d\n", + __FUNCTION__,(UINTN)CurrentBlock)); + + Status = NorFlashPlatformRead (Instance, CurrentBlock, (UINTN)0 , + BlockSizeInBytes,ReadBuffer); + 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 *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 ; + + 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; + + WriteBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Program data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; + BlockCount++, CurrentBlock++, + WriteBuffer = (WriteBuffer + 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, WriteBuffer); + 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/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; + + 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; + + 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 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