From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM11-CO1-obe.outbound.protection.outlook.com (NAM11-CO1-obe.outbound.protection.outlook.com [40.107.220.138]) by mx.groups.io with SMTP id smtpd.web08.4053.1607505868381477498 for ; Wed, 09 Dec 2020 01:24:28 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@os.amperecomputing.com header.s=selector2 header.b=PgAHuIpt; spf=pass (domain: os.amperecomputing.com, ip: 40.107.220.138, mailfrom: nhi@os.amperecomputing.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=AaNLDdDTf0rIgab4KUGrPYssBWSAJNgvboIzrQG9D68bG4UdEv0lgBAipTJvrjhDQSdgnfsXoCm3dhCwVnRmF9q+/xcXKWvnUEOZGtG0U088UNiqwjKwsVZRc6THAifMD72E4lCQgjLyyvxVNhbw2lTTxDN6tmbMD39cPl5vVqAPdEA8w/d5EhWKp0EaesO8hLOrzkcvrNdmVUI+r/qbSihW5ZGEsIomo8t+n0drbLYDcPnOJBEl5jIxo1Eorb/TskHunzBceGdOqq5P+rwO9IbVtmt6igaP30E1BWwwoTqujU5+Jw3AAY0oCir3Ci+UuzZoIe2WxpsGkgR9eLyz1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=C7ntNNhUUCDtm0AeP+NaTN1dlaUVutgpGsPG1NuQBNc=; b=ViCVArUEcqNM/rt4JzXKEvsDUskPWnG3pHnMbe8KeUOQpxAOXDIi7ovRYct1YVshhs8AD0N8uzAm/YZarYOSPVBeRgbKdOeN1C9uk9Z7qXQCnYcg9wMTzCZMa48FGMV8zaNAy08TkV2X80J2lwtmoaImACA4MNGuUjTwSfdYL+QK74YCjACtVNrOWhDgImK2lvwKAsngfHh4QNpfjH6rfAk7qlw8/u/sVKfJP2zNLBnYFos1iFU9ceboKzEbCxHO+WbWqlm1X+kyXa/+c6ZIgUk6JFMKByj4vT4x/zjitvNrdzdbpkFyWORcQISOXr/tfGesuhr8xoD226+qFZDtqg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=C7ntNNhUUCDtm0AeP+NaTN1dlaUVutgpGsPG1NuQBNc=; b=PgAHuIpt24md6kKRyI56yQzZbCauztwmy42gW1THwvwGlo5monFfln0SHTm2d8rCa4CDY0rMJ1b/dbAkrwXyF7WCHXl51sP0jdBvs6ytlx7lyDCpwkxLbSabFGR0DvaHsIHsI+Eoduz39fdg2PIP9ufuHWWSOb30bqkFbCh2puM= Authentication-Results: edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=none action=none header.from=os.amperecomputing.com; Received: from DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) by DM6PR01MB5609.prod.exchangelabs.com (2603:10b6:5:157::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3632.21; Wed, 9 Dec 2020 09:24:26 +0000 Received: from DM6PR01MB5849.prod.exchangelabs.com ([fe80::c814:9a08:5c2e:4076]) by DM6PR01MB5849.prod.exchangelabs.com ([fe80::c814:9a08:5c2e:4076%5]) with mapi id 15.20.3632.023; Wed, 9 Dec 2020 09:24:26 +0000 From: "Nhi Pham" To: devel@edk2.groups.io Cc: Vu Nguyen Subject: [edk2-platforms][PATCH 10/34] Silicon/Ampere: Support Non Volatile storage for Variable service Date: Wed, 9 Dec 2020 16:25:07 +0700 Message-Id: <20201209092531.30867-11-nhi@os.amperecomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201209092531.30867-1-nhi@os.amperecomputing.com> References: <20201209092531.30867-1-nhi@os.amperecomputing.com> X-Originating-IP: [118.69.219.201] X-ClientProxiedBy: HK0PR01CA0054.apcprd01.prod.exchangelabs.com (2603:1096:203:a6::18) To DM6PR01MB5849.prod.exchangelabs.com (2603:10b6:5:205::20) Return-Path: nhi@os.amperecomputing.com MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from sw004.amperecomputing.com (118.69.219.201) by HK0PR01CA0054.apcprd01.prod.exchangelabs.com (2603:1096:203:a6::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3654.12 via Frontend Transport; Wed, 9 Dec 2020 09:24:25 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 41c77354-dd7e-4f29-6edc-08d89c24390d X-MS-TrafficTypeDiagnostic: DM6PR01MB5609: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:10000; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 8Uenwr8F3yrBgtch34LvR2G6syxgmYR7eB3uCaUjlqlE4nv5oPwZ0Pi7LqdNd5BULr2dO1baXRc/PylICk89vmqU9zRNdHEyc8ULEcJsIxCeghvrMcqvjVtCjurMr/e4uqKUl0aPq/eVujqL4ni8cb1gybwp4GpwzCmjWLzeBJMoDFQ5jnMhQZwabmRXVVZHjrSHaF+md1RaM3ZxkmfdfEuAeUJt3bl/cIWzeRSUX+sjjPzzYslTXx5wwrT226uA8UAkEVRb+42ud7DulygE/HKSZGPiP5ZbJTWLSoq1V25mu7A6ASIIVJ058k7s+6weoMOINKYOhmXeGe79mDgIBljEDvJfg23IY0GPv5y3HdzE7yJX2BT/qn5MMSRf4f1yJORpyNtx+iWwq6JnaRNijQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM6PR01MB5849.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(376002)(136003)(346002)(366004)(5660300002)(956004)(508600001)(52116002)(30864003)(66946007)(6916009)(2616005)(1076003)(19627235002)(86362001)(6512007)(66476007)(26005)(8936002)(16526019)(107886003)(6666004)(186003)(6486002)(8676002)(6506007)(83380400001)(2906002)(34490700003)(66556008)(4326008)(559001)(579004)(44824005);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData: =?us-ascii?Q?PrpmGPVI3wVUo7FC/Y2we/3FK8q4usPs0dtPuUPTnb1lr1M3QDkZ5gGbqigw?= =?us-ascii?Q?Ycs6CKgMYJzYOK7mce1P05FHCQ4F4nIfz0KpDZD54zJ8lNiz7czI08CscIaN?= =?us-ascii?Q?g0ssMg6IYGwt8MMQiDxfTLJKb8WAZ3e1OHvWRZAfwQasJIBQ9fhacCMM1NHv?= =?us-ascii?Q?fUzOoIJB4s0mtLYEYj1X0CneHBohbljSEF4izm+cWfI5vGRX0SqQrRLKEwwT?= =?us-ascii?Q?iyK0hL6MOhMFgWbT/eYDiVi8dh9P0cUhMt25iz0EZ/3wuhK13lMEVaTZ1y66?= =?us-ascii?Q?W4n9ZJLqFnImQxw90RJGA0xme/Xgjl64yKYUUmi3rS8Ps0T456EaSdjqYyCP?= =?us-ascii?Q?6ufoGTU2hPIf1qw/EctxvsIIh+JB8J5E200AzlFo+M7KTLukRg+BBcUmXqb3?= =?us-ascii?Q?o5Wct5dSOimpiHRg2XWEIHzjIRd6QblB43RYU1Q1mOiCJCh+VqzGOknYnqfk?= =?us-ascii?Q?x6AW+noJgHV2Tl7ok56pl324OzkkUdSQszK8cktJdqICJGeIPDDz5h9uM5Ko?= =?us-ascii?Q?LuwJceRFdYljn1BtOxPg1YSNm54FxAhsylt9lh8jwLRr7hQjo/vIHIg2Mcb5?= =?us-ascii?Q?lw5NkitraRBBIYWaYWpUSE1fieRsF54BO6+3P/9CEfHovgu6/cES0UyRfgOk?= =?us-ascii?Q?/sUzMRa4hI+jRt1Wnvq0NcTmxYA8t7KUIX1G40DnlBFeBW4nyJcMF2fqJQhr?= =?us-ascii?Q?obMTI/zs/954WcKDMsUtDZUbNFzyRb0JoUlFQ4JpiGsU3FY2ACYtJk4mmK3C?= =?us-ascii?Q?ImPVZ7keYG+FR0cS8In7daXwCmbrlK518pevQpRQkhj+J6nvkkRkwtvL+97r?= =?us-ascii?Q?pq830FFECPgvDb1nZo8SZkFahBBSA7rVHtj5fxWUqpnyEfNU9wgXA02Zcz2U?= =?us-ascii?Q?jgj0szY/15K3ihTfC55r+1aztbMJVDA4+5HCF6tc1xOV0Sf7QLZa8lUneRf/?= =?us-ascii?Q?iV2//Xhik8pVVTEIvRqw6CsMuLMZKybm/1RQme/OvOiSshnO/SQVhR/6pgon?= =?us-ascii?Q?XbzS?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-AuthSource: DM6PR01MB5849.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Dec 2020 09:24:26.1623 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-Network-Message-Id: 41c77354-dd7e-4f29-6edc-08d89c24390d X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: S9EBAU4H6uLJPatK2OZIpXkr6F7uhyQ0W3CfDdXnn1IL+Jw8ycHxO/wWDJTh16SmlyRxd+gSRD0bRLQj4gYIrXGJujGJ3XWEYXWDbEfFOJ0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR01MB5609 Content-Type: text/plain From: Vu Nguyen Switch to use Flash as the storage for Variable services. Accessing to Flash was done by using MM communication protocol. This change includes three parts: - MmCommunication provide functions to communicate with secure partition in PEI and DXE phase. - FlashPei is to verify current stored data on Flash by comparing saved UUID with firmware's UEFI_UUID. If they are identical, stored data to RAM, otherwise replace stored data with default value from NVRAM Fv. - FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be used as a backend for VariableDxe to get/set variables. Test cases: - Enter UEFI menu, change settings and verify these values at next boot. - For runtime, use efibootmgr Linux command to change EFI variables (BootNext, BootTime,...) and verify at next boot. Signed-off-by: Vu Nguyen --- Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec | 3 + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc | 7 +- Platform/Ampere/JadePkg/Jade.dsc | 1 + Platform/Ampere/JadePkg/Jade.fdf | 57 ++- Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf | 55 ++ Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf | 48 ++ Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf | 36 ++ Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h | 42 ++ Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c | 524 ++++++++++++++++++++ Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c | 276 +++++++++++ Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c | 357 +++++++++++++ 11 files changed, 1403 insertions(+), 3 deletions(-) diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec index c34d580255b9..cc513d8ac69f 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec +++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec @@ -37,6 +37,9 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to communicate with PMPro. PMProLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/PMProLib.h + ## @libraryclass Defines a set of methods to access flash memory. + FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h + [Guids] ## SPI NOR Proxy MM GUID diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc index ecd67511a8be..3fc1fd94ee62 100755 --- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc +++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc @@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] [BuildOptions] GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG + GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID) [LibraryClasses.common] !if $(TARGET) == RELEASE @@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER] SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf [LibraryClasses.common.UEFI_APPLICATION] UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf @@ -262,6 +264,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER] EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamDxeLib/NVParamDxeLib.inf + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf [LibraryClasses.ARM,LibraryClasses.AARCH64] # @@ -519,6 +522,7 @@ [Components.common] Silicon/Ampere/Drivers/ATFHobPei/ATFHobPeim.inf Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf ArmPkg/Drivers/CpuPei/CpuPei.inf UefiCpuPkg/CpuIoPei/CpuIoPei.inf MdeModulePkg/Universal/Variable/Pei/VariablePei.inf @@ -571,10 +575,9 @@ [Components.common] # # Environment Variables Protocol # + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { - - gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc index e92d5079c3a0..66f1b6ab94d2 100755 --- a/Platform/Ampere/JadePkg/Jade.dsc +++ b/Platform/Ampere/JadePkg/Jade.dsc @@ -31,6 +31,7 @@ [Defines] DEFINE EDK2_SKIP_PEICORE = TRUE DEFINE SECURE_BOOT_ENABLE = FALSE DEFINE INCLUDE_TFTP_COMMAND = TRUE + DEFINE UEFI_UUID = 21A80447-B2DD-4D8C-BCA2-04305F025EA4 # # Network definition diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf index 321156fb8f60..8efbd79461de 100755 --- a/Platform/Ampere/JadePkg/Jade.fdf +++ b/Platform/Ampere/JadePkg/Jade.fdf @@ -58,8 +58,59 @@ [FD.BL33_JADE_UEFI] # NV Variables # Offset: 0x000C0000 # Size: 0x00080000 -# T.B.D # +0x000C0000|0x00030000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize +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: 0x80000 + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + # Signature "_FVH" # Attributes + 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00, + # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision + 0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02, + # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 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: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) - + # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8 + # This can speed up the Variable Dispatch a bit. + 0xB8, 0xFF, 0x02, 0x00, + # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32 + 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +0x000F0000|0x00010000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize +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 + 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF, + # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0 + 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +0x00100000|0x00040000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize # # NVRAM Backup @@ -123,6 +174,7 @@ [FV.FV_PEI] INF Silicon/Ampere/Drivers/ATFHobPei/ATFHobPeim.inf INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf INF ArmPkg/Drivers/CpuPei/CpuPei.inf INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf @@ -157,6 +209,7 @@ [FV.FvMain] INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf } INF MdeModulePkg/Core/Dxe/DxeMain.inf @@ -185,6 +238,8 @@ [FV.FvMain] # Environment Variables Protocol # INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf # # Multiple Console IO support diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf new file mode 100644 index 000000000000..26516d0d0efb --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf @@ -0,0 +1,55 @@ +## @file +# +# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = FlashFvbDxe + FILE_GUID = 9E6EA240-DF80-11EA-8B6E-0800200C9A66 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = FlashFvbDxeInitialize + +[Sources] + FlashFvbDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Ampere/AmperePkg.dec + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec + +[LibraryClasses] + DebugLib + PcdLib + FlashLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeLib + + +[FixedPcd] + gAmpereTokenSpaceGuid.PcdFvBlockSize + + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + +[Guids] + gEfiEventVirtualAddressChangeGuid + gSpiNorMmGuid + +[Protocols] + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES + gEfiMmCommunicationProtocolGuid ## CONSUMES + +[Depex] + gEfiMmCommunicationProtocolGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf new file mode 100644 index 000000000000..b4c086800256 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf @@ -0,0 +1,48 @@ +## @file +# +# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = FlashPei + FILE_GUID = 967CFBD0-DF81-11EA-8B6E-0800200C9A66 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = FlashPeiEntryPoint + +[Sources] + FlashPei.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Ampere/AmperePkg.dec + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec + +[LibraryClasses] + ArmSmcLib + BaseMemoryLib + DebugLib + MmCommunicationLib + PeimEntryPoint + +[Guids] + gSpiNorMmGuid + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + +[Depex] + TRUE diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf new file mode 100644 index 000000000000..a5f7a4ceff1d --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf @@ -0,0 +1,36 @@ +## @file +# +# Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = FlashLib + FILE_GUID = 9E9D093D-6484-45AE-BA49-0745AA0BB481 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.1 + LIBRARY_CLASS = FlashLib + CONSTRUCTOR = FlashLibConstructor + +[Sources.common] + FlashLib.c + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + +[Guids] + gSpiNorMmGuid + +[Protocols] + gEfiMmCommunicationProtocolGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h new file mode 100644 index 000000000000..18f12d4c86ef --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h @@ -0,0 +1,42 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FLASH_LIB_H__ +#define __FLASH_LIB_H__ + +EFI_STATUS +EFIAPI +FlashGetNvRamInfo ( + OUT UINT64 *NvRamBase, + OUT UINT32 *NvRamSize + ); + +EFI_STATUS +EFIAPI +FlashEraseCommand ( + IN UINT8 *pBlockAddress, + IN UINT32 Length + ); + +EFI_STATUS +EFIAPI +FlashProgramCommand ( + IN UINT8 *pByteAddress, + IN UINT8 *Byte, + IN OUT UINTN *Length + ); + +EFI_STATUS +EFIAPI +FlashReadCommand ( + IN UINT8 *pByteAddress, + OUT UINT8 *Byte, + IN OUT UINTN *Length + ); + +#endif /* __FLASH_LIB_H__ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c new file mode 100644 index 000000000000..7428f9c17111 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c @@ -0,0 +1,524 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +// +// These temporary buffers are used to calculate and convert linear virtual +// to physical address +// +STATIC UINT64 mNvFlashBase; +STATIC UINT32 mNvFlashSize; +STATIC UINT32 mFlashBlockSize; +STATIC UINT64 mNvStorageBase; +STATIC UINT64 mNvStorageSize; + +/** + 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 +FlashFvbAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **) &mNvStorageBase); +} + +/** + 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 +FlashFvbDxeGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + ASSERT (Attributes != NULL); + + *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be 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_ALIGNMENT | + EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1') + + 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 +FlashFvbDxeSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + return EFI_SUCCESS; // ignore for now +} + +/** + 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_UNSUPPORTED The firmware volume is not memory mapped. + +**/ +EFI_STATUS +EFIAPI +FlashFvbDxeGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + ASSERT (Address != NULL); + + *Address = (EFI_PHYSICAL_ADDRESS) mNvStorageBase; + + 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 +FlashFvbDxeGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +{ + UINTN TotalNvStorageBlocks; + + ASSERT (BlockSize != NULL); + ASSERT (NumberOfBlocks != NULL); + + TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize; + + if (TotalNvStorageBlocks <= (UINTN) Lba) { + DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n")); + return EFI_INVALID_PARAMETER; + } + + *NumberOfBlocks = TotalNvStorageBlocks - (UINTN) Lba; + *BlockSize = mFlashBlockSize; + + return EFI_SUCCESS; +} + +/** + 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 +FlashFvbDxeRead ( + 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 Status; + + ASSERT (NumBytes != NULL); + ASSERT (Buffer != NULL); + + if (Offset + *NumBytes > mFlashBlockSize) { + return EFI_BAD_BUFFER_SIZE; + } + + Status = FlashReadCommand ( + (UINT8 *) (mNvFlashBase + Lba * mFlashBlockSize + Offset), + Buffer, + NumBytes + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to do flash read\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Writes the specified number of bytes from the input buffer to the block. + + The Write() function writes the specified number of bytes from + the provided buffer to the specified block and offset. If the + firmware volume is sticky write, the caller must ensure that + all the bits of the specified range to write are in the + EFI_FVB_ERASE_POLARITY state before calling the Write() + function, or else the result will be unpredictable. This + unpredictability arises because, for a sticky-write firmware + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY + state but cannot flip it back again. Before calling the + Write() function, it is recommended for the caller to first call + the EraseBlocks() function to erase the specified block to + write. A block erase cycle will transition bits from the + (NOT)EFI_FVB_ERASE_POLARITY state back to the + EFI_FVB_ERASE_POLARITY state. Implementations should be + mindful that the firmware volume might be in the WriteDisabled + state. If it is in this state, the Write() function must + return the status code EFI_ACCESS_DENIED without modifying the + contents of the firmware volume. The Write() function must + also prevent spanning block boundaries. If a write is + requested that spans a block boundary, the write must store up + to the boundary but not beyond. The output parameter NumBytes + must be set to correctly indicate the number of bytes actually + written. The caller must be aware that a write may be + partially completed. All writes, partial or otherwise, must be + fully flushed to the hardware before the Write() service + returns. + + @param This 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 +FlashFvbDxeWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + + ASSERT (NumBytes != NULL); + ASSERT (Buffer != NULL); + + if (Offset + *NumBytes > mFlashBlockSize) { + return EFI_BAD_BUFFER_SIZE; + } + + Status = FlashProgramCommand ( + (UINT8 *) (mNvFlashBase + Lba * mFlashBlockSize + Offset), + Buffer, + NumBytes + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to do flash program\n")); + return EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Erases and initializes 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 +FlashFvbDxeErase ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ) +{ + VA_LIST Args; + EFI_LBA Start; + UINTN Length; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + VA_START (Args, This); + + for (Start = VA_ARG (Args, EFI_LBA); + Start != EFI_LBA_LIST_TERMINATOR; + Start = VA_ARG (Args, EFI_LBA)) { + Length = VA_ARG (Args, UINTN); + Status = FlashEraseCommand ( + (UINT8 *) (mNvFlashBase + Start * mFlashBlockSize), + Length * mFlashBlockSize + ); + } + + VA_END (Args); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = { + FlashFvbDxeGetAttributes, + FlashFvbDxeSetAttributes, + FlashFvbDxeGetPhysicalAddress, + FlashFvbDxeGetBlockSize, + FlashFvbDxeRead, + FlashFvbDxeWrite, + FlashFvbDxeErase +}; + +EFI_STATUS +EFIAPI +FlashFvbDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle = NULL; + EFI_EVENT VirtualAddressChangeEvent; + + // Get NV store FV info + mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize); + mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64); + mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize); + + DEBUG (( + DEBUG_INFO, + "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n", + __FUNCTION__, + mNvStorageBase, + mNvStorageSize + )); + + // Get NV Flash information + Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + + if (mNvFlashSize >= (mNvStorageSize * 2)) { + DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__)); + } else { + DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FlashFvbAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &VirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &mFlashFvbProtocol, + NULL + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n")); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c new file mode 100644 index 000000000000..3fd5a709e58e --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c @@ -0,0 +1,276 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// Convert to string +#define _STR(x) #x + +// Make sure the argument is expanded before converting to string +#define STR(x) _STR(x) + +// Use dynamic UEFI_UUID of each build time +#define UEFI_UUID_BUILD STR(UEFI_UUID) + +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq; + +STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)]; +STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)]; + +STATIC +EFI_STATUS +UefiMmCreateSpiNorReq ( + VOID *Data, + UINT64 Size + ) +{ + CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid); + mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size; + + if (Size != 0) { + ASSERT (Data); + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE); + + CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size); + } + + return EFI_SUCCESS; +} + +/** + Entry point function for the PEIM + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @return EFI_SUCCESS If we installed our PPI + +**/ +EFI_STATUS +EFIAPI +FlashPeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + UINT64 FWNvRamStartOffset; + EFI_STATUS Status; + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes; + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes; + UINT64 MmData[5]; + UINTN Size; + VOID *NvRamAddress; + UINTN NvRamSize; + +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE) + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes; + UINT64 NV2Base, NV2Size; +#endif + + NvRamAddress = (VOID *) PcdGet64 (PcdFlashNvStorageVariableBase64); + NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize); + + /* Find out about the start offset of NVRAM to be passed to SMC */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR(Status); + + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) { + /* Old FW so just exit */ + return EFI_SUCCESS; + } + FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase; + + CopyMem ((VOID *) mBuildUuid, (VOID *) UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD)); + if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) { + /* NVRAM size provided by FW is not enough */ + return EFI_INVALID_PARAMETER; + } + + /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_READ; + MmData[1] = (UINT64) (FWNvRamStartOffset + NvRamSize * 2); + MmData[2] = (UINT64) sizeof (mStoredUuid); + MmData[3] = (UINT64) mStoredUuid; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR(Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + + if (CompareMem ((VOID *) mStoredUuid, (VOID *) mBuildUuid, sizeof (mBuildUuid))) { + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_ERASE; + MmData[1] = (UINT64) FWNvRamStartOffset; + MmData[2] = (UINT64) (NvRamSize * 2); + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR (Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_WRITE; + MmData[1] = (UINT64) FWNvRamStartOffset; + MmData[2] = (UINT64) (NvRamSize * 2); + MmData[3] = (UINT64) NvRamAddress; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR (Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + + /* Update UUID */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_ERASE; + MmData[1] = (UINT64) (FWNvRamStartOffset + NvRamSize * 2); + MmData[2] = (UINT64) sizeof (mBuildUuid); + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR(Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_WRITE; + MmData[1] = (UINT64) (FWNvRamStartOffset + NvRamSize * 2); + MmData[2] = (UINT64) sizeof (mBuildUuid); + MmData[3] = (UINT64) mBuildUuid; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR (Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + DEBUG((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n")); + } else { + /* Copy the stored NVRAM to RAM */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_READ; + MmData[1] = (UINT64) FWNvRamStartOffset; + MmData[2] = (UINT64) (NvRamSize * 2); + MmData[3] = (UINT64) NvRamAddress; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR (Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + return Status; + } + DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n")); + } + +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE) + /* Find out about the start offset of NVRAM2 to be passed to SMC */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *) &mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR (Status); + + MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad; + if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) + { + NV2Base = MmSpiNorNV2InfoRes->NVBase; + NV2Size = MmSpiNorNV2InfoRes->NVSize; + /* Make sure the requested size is smaller than allocated */ + if (RAM_BLOCKIO_SIZE <= NV2Size) { + /* Copy the ramdisk image to RAM */ + ZeroMem ((VOID *)MmData, sizeof (MmData)); + MmData[0] = MM_SPINOR_FUNC_READ; + MmData[1] = (UINT64) NV2Base; /* Start virtual address */ + MmData[2] = (UINT64) RAM_BLOCKIO_SIZE; + MmData[3] = (UINT64) RAM_BLOCKIO_START_ADDRESS; + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof(MmData)); + + Size = sizeof(EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof(MmData); + Status = MmCommunicationCommunicate ( + (VOID *)&mEfiMmSpiNorReq, + &Size + ); + ASSERT_EFI_ERROR(Status); + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad; + ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS); + } + + BuildMemoryAllocationHob ((EFI_PHYSICAL_ADDRESS) RAM_BLOCKIO_START_ADDRESS, + EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE, EfiLoaderData); + } +#endif + + return EFI_SUCCESS; +} diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c new file mode 100644 index 000000000000..6826c5032086 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c @@ -0,0 +1,357 @@ +/** @file + + Copyright (c) 2020, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL; +STATIC EFI_MM_COMM_REQUEST *mCommBuffer = NULL; + +BOOLEAN mIsEfiRuntime; +UINT8 *mTmpBufVirt; +UINT8 *mTmpBufPhy; + +/** + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + event. It converts a pointer to a new virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +FlashLibAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0x0, (VOID **) &mTmpBufVirt); + gRT->ConvertPointer (0x0, (VOID **) &mCommBuffer); + gRT->ConvertPointer (0x0, (VOID **) &mMmCommunicationProtocol); + + mIsEfiRuntime = TRUE; +} + +EFI_STATUS +EFIAPI +FlashLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_EVENT VirtualAddressChangeEvent = NULL; + EFI_STATUS Status = EFI_SUCCESS; + + mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST)); + ASSERT (mCommBuffer != NULL); + + mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE); + mTmpBufVirt = mTmpBufPhy; + ASSERT (mTmpBufPhy != NULL); + + Status = gBS->LocateProtocol ( + &gEfiMmCommunicationProtocolGuid, + NULL, + (VOID **) &mMmCommunicationProtocol + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEvent ( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + TPL_CALLBACK, + FlashLibAddressChangeEvent, + NULL, + &VirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FlashMmCommunicate ( + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize + ) +{ + if (mMmCommunicationProtocol == NULL) { + return EFI_INVALID_PARAMETER; + } + + return mMmCommunicationProtocol->Communicate ( + mMmCommunicationProtocol, + CommBuffer, + CommSize + ); +} + +STATIC +EFI_STATUS +UefiMmCreateSpiNorReq ( + IN VOID *Data, + IN UINT64 Size + ) +{ + if (mCommBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid); + mCommBuffer->EfiMmHdr.MsgLength = Size; + + if (Size != 0) { + ASSERT (Data); + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE); + + CopyMem (mCommBuffer->PayLoad.Data, Data, Size); + } + + return EFI_SUCCESS; +} + +/** + Convert Virtual Address to Physical Address at Runtime Services + + @param VirtualPtr Virtual Address Pointer + @param Size Total bytes of the buffer + + @retval Ptr Return the pointer of the converted address + +**/ +STATIC +UINT8 * +ConvertVirtualToPhysical ( + IN UINT8 *VirtualPtr, + IN UINTN Size + ) +{ + if (mIsEfiRuntime) { + ASSERT (VirtualPtr != NULL); + CopyMem ((VOID *) mTmpBufVirt, (VOID *) VirtualPtr, Size); + return (UINT8 *) mTmpBufPhy; + } + + return (UINT8 *) VirtualPtr; +} + +/** + Convert Physical Address to Virtual Address at Runtime Services + + @param VirtualPtr Physical Address Pointer + @param Size Total bytes of the buffer + +**/ +STATIC +VOID +ConvertPhysicaltoVirtual ( + IN UINT8 *PhysicalPtr, + IN UINTN Size + ) +{ + if (mIsEfiRuntime) { + ASSERT (PhysicalPtr != NULL); + CopyMem ((VOID *) PhysicalPtr, (VOID *) mTmpBufVirt, Size); + } +} + +EFI_STATUS +EFIAPI +FlashGetNvRamInfo ( + OUT UINT64 *NvRamBase, + OUT UINT32 *NvRamSize + ) +{ + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes; + EFI_STATUS Status; + UINT64 MmData[5]; + UINTN Size; + + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO; + + Status = UefiMmCreateSpiNorReq ((VOID *) &MmData, sizeof (MmData)); + if (EFI_ERROR (Status)) { + return Status; + } + + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); + Status = FlashMmCommunicate ( + mCommBuffer, + &Size + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *) &mCommBuffer->PayLoad; + if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) { + *NvRamBase = MmSpiNorNVInfoRes->NVBase; + *NvRamSize = MmSpiNorNVInfoRes->NVSize; + DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FlashEraseCommand ( + IN UINT8 *pBlockAddress, + IN UINT32 Length + ) +{ + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes; + EFI_STATUS Status; + UINT64 MmData[5]; + UINTN Size; + + ASSERT (pBlockAddress != NULL); + + MmData[0] = MM_SPINOR_FUNC_ERASE; + MmData[1] = (UINT64) pBlockAddress; + MmData[2] = Length; + + Status = UefiMmCreateSpiNorReq ((VOID *) &MmData, sizeof (MmData)); + if (EFI_ERROR (Status)) { + return Status; + } + + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); + Status = FlashMmCommunicate ( + mCommBuffer, + &Size + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *) &mCommBuffer->PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FlashProgramCommand ( + IN UINT8 *pByteAddress, + IN UINT8 *Byte, + IN OUT UINTN *Length + ) +{ + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes; + EFI_STATUS Status; + UINT64 MmData[5]; + UINTN Remain, Size, NumWrite; + UINTN Count = 0; + + ASSERT (pByteAddress != NULL); + ASSERT (Byte != NULL); + ASSERT (Length != NULL); + + Remain = *Length; + while (Remain > 0) { + NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain; + + MmData[0] = MM_SPINOR_FUNC_WRITE; + MmData[1] = (UINT64) pByteAddress; + MmData[2] = NumWrite; + MmData[3] = (UINT64) ConvertVirtualToPhysical (Byte + Count, NumWrite); + + Status = UefiMmCreateSpiNorReq ((VOID *) &MmData, sizeof (MmData)); + if (EFI_ERROR (Status)) { + return Status; + } + + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); + Status = FlashMmCommunicate ( + mCommBuffer, + &Size + ); + if (EFI_ERROR(Status)) { + return Status; + } + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *) &mCommBuffer->PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status)); + return EFI_DEVICE_ERROR; + } + + Remain -= NumWrite; + Count += NumWrite; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FlashReadCommand ( + IN UINT8 *pByteAddress, + OUT UINT8 *Byte, + IN OUT UINTN *Length + ) +{ + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes; + EFI_STATUS Status; + UINT64 MmData[5]; + UINTN Remain, Size, NumRead; + UINTN Count = 0; + + ASSERT (pByteAddress != NULL); + ASSERT (Byte != NULL); + ASSERT (Length != NULL); + + Remain = *Length; + while (Remain > 0) { + NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain; + + MmData[0] = MM_SPINOR_FUNC_READ; + MmData[1] = (UINT64) pByteAddress; + MmData[2] = NumRead; + MmData[3] = (UINT64) ConvertVirtualToPhysical (Byte + Count, NumRead); + + Status = UefiMmCreateSpiNorReq ((VOID *) &MmData, sizeof (MmData)); + if (EFI_ERROR (Status)) { + return Status; + } + + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData); + Status = FlashMmCommunicate ( + mCommBuffer, + &Size + ); + if (EFI_ERROR(Status)) { + return Status; + } + + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *) &mCommBuffer->PayLoad; + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status)); + return EFI_DEVICE_ERROR; + } + + ConvertPhysicaltoVirtual (Byte + Count, NumRead); + Remain -= NumRead; + Count += NumRead; + } + + return EFI_SUCCESS; +} -- 2.17.1