From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by mx.groups.io with SMTP id smtpd.web08.126.1668446375864639681 for ; Mon, 14 Nov 2022 09:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=FlavvDHf; spf=pass (domain: intel.com, ip: 134.134.136.20, mailfrom: judah.vang@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668446375; x=1699982375; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-transfer-encoding:mime-version; bh=t1zwr5Zjgcu2W3N9iW6AsRRgdlXvD189Xlbc4gx/UUM=; b=FlavvDHfHaVGr+HaIuerxU2pcnDK0r5hHgnIqu4in7xu4wh6ghilpjXH jkmas7WQhHxqg9ZlvbqfLcvbd4WolX8ugDimVkRhzBjDxaSlkrQwbQnAZ Jp7iCXBwp2Z+kPvjwXB7mh0FreYxkawbiE4WI0sjm5Sr5xaKGcjXSiW9h GZkdwCqsPgSR/hIEajX+QyyXlQGtOsMaLPYpMDNFn3ajbgLgJejvzMdYl KFwqwmzyY6L/kWgAC2kTwhzsi5/9pLPr3GFIaAmhw3Pk6YAmQXPY54L4T r6WN785Snx9zWUKnhqQM97uOHL7V3cWe71bGyzRs1YwdFmleM6wpBSIiq A==; X-IronPort-AV: E=McAfee;i="6500,9779,10531"; a="299547884" X-IronPort-AV: E=Sophos;i="5.96,164,1665471600"; d="scan'208";a="299547884" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Nov 2022 09:19:34 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10531"; a="813337964" X-IronPort-AV: E=Sophos;i="5.96,164,1665471600"; d="scan'208";a="813337964" Received: from orsmsx601.amr.corp.intel.com ([10.22.229.14]) by orsmga005.jf.intel.com with ESMTP; 14 Nov 2022 09:19:33 -0800 Received: from orsmsx611.amr.corp.intel.com (10.22.229.24) by ORSMSX601.amr.corp.intel.com (10.22.229.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Mon, 14 Nov 2022 09:19:33 -0800 Received: from orsmsx603.amr.corp.intel.com (10.22.229.16) by ORSMSX611.amr.corp.intel.com (10.22.229.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Mon, 14 Nov 2022 09:19:32 -0800 Received: from ORSEDG601.ED.cps.intel.com (10.7.248.6) by orsmsx603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31 via Frontend Transport; Mon, 14 Nov 2022 09:19:32 -0800 Received: from NAM02-SN1-obe.outbound.protection.outlook.com (104.47.57.42) by edgegateway.intel.com (134.134.137.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2375.31; Mon, 14 Nov 2022 09:19:32 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Q4b3HCY8lKGf5mMK5aatYIZBg/POhqxOAt1xTXJ7BxP9ryId7xEGhgknjfOpKkS5gA0HqC9c8h85VX9kUcWFqnioZ/0TFEKoWdEo+5pMgly2jJr3R7ogfs6wrCaolPM4wJm5zRDkXzX0RBo520IPAaQzAASOcNQs6HycMI1BF8ugZt9zfHaYechhtQm9F/rmTrjVNRShhW7RE15HEgG6Yt2ZP8d9gHSywvKRPiFGtZBvnSbMOIk7W8rX+z2bJHADEpa89+O4sVLKX1Gvb7uRZ2cFmOUYRPbnmgKOMryAQkr8Lor1dNplTUOVFDIsHsLg6URm51KAmJRJbQqnWFohhw== 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=O6+5VpOwAYspKFdKGp35rLKvyQsrDjSpyHv+e7cF9lI=; b=Ou2orTl4DJiJjC2If6JS5ivDmzVcvFlCbnY4aLpxOGY4CFT2miR7EcqeHGoa4PGND6+ybSkIuq4xpEVR/SZX3BvHXppQsC47gde5Wz3hJQgliKcukEXyPtrd0yOQOo7CY3iVqDVUNY9zKPuwQw57PSh4o2icM4vgCfaP5wsJ6YvDY2KIayIKiGxWCUWRKtVMpu0NcICyrkjs0mjTU9MfEJ+wmDwp/PFFPl+mmgBMrkGggsiEgfUZ7HIrtxzJt3U39uSiXKmjgvOmceujAP6ZnOT7aBKEVg/QpSJ+aBSqmaJSv2ORXEcI+/33w8LQfHlgM4gV91fblf3Y1eu2DR6KKA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none Received: from BL3PR11MB6434.namprd11.prod.outlook.com (2603:10b6:208:3ba::22) by DM6PR11MB4561.namprd11.prod.outlook.com (2603:10b6:5:2ae::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5813.17; Mon, 14 Nov 2022 17:19:16 +0000 Received: from BL3PR11MB6434.namprd11.prod.outlook.com ([fe80::f170:5a2e:d56a:e3fa]) by BL3PR11MB6434.namprd11.prod.outlook.com ([fe80::f170:5a2e:d56a:e3fa%5]) with mapi id 15.20.5813.017; Mon, 14 Nov 2022 17:19:15 +0000 From: "Judah Vang" To: "Wang, Jian J" , "devel@edk2.groups.io" CC: "Gao, Liming" , "Wu, Hao A" , "Mistry, Nishant C" Subject: Re: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Thread-Topic: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variables Thread-Index: AQHY8bJeEew8D/uC3EqqEu9taD1+Ya49vySQgAD3MJA= Date: Mon, 14 Nov 2022 17:19:14 +0000 Message-ID: References: <20221106073509.3071-1-judah.vang@intel.com> <20221106073509.3071-9-judah.vang@intel.com> In-Reply-To: Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.6.500.17 dlp-reaction: no-action authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=intel.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: BL3PR11MB6434:EE_|DM6PR11MB4561:EE_ x-ms-office365-filtering-correlation-id: f1a7c5f6-4dd8-4115-5211-08dac6645b37 x-ld-processed: 46c98d88-e344-4ed4-8496-4ed7712e255d,ExtAddr x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: 5N6ya8EubnQRElN+fVS+e0EzEZLDbex3Ev9/Fyda29olYYQLOmL+YOW+Cw/evLdByI+e6+bxwyhKoUGtEGbdy2WlfA8f7n2Bxk59f8AQIIfJQSZ2gYQTr6zkYB2fyFTikJrYgzqLrqXf2VWp54vWpKn55BSs0MDv9DxCzD8IZw9edm9Fz/oRD+Sw7mn0e6RSoY/iAgyoWiLeCS0j8ZDx9C6VP6AHkHsplYgPJTEcGan2np4q4KM0vn+AktQ1bxxKVNLPyN/+Zxr0RBs4di3XHniTOFTt85Y5eXmNe95K1mq0/xAzOt1HJ29hOnvryy65qlWXMGBxg2FqLnYRmrXJvHnctP6lgyLgkBp6wZQXe448eHSXAj7SK+1dJEm69qbSEMN5mMXJFex+AtpBezyX4IcqUb+3gH+0M2IZRm4BU5VMuY34cLkkByXzqpoxUMFHRGizRWw2RwYJqeH+JPyYHgIvn0LTqDxuTR8DL/47+vDRHL90SMXlYroYvVlFMQlyRge6hAAbfZsN/yWVmMn+51rjhye1h96191wHdQ/DJlWZUllXdzo+LEMEild2jwiTttV6VTW/X/wZ/jwRB7zqUm1SgeT4eVYYFqCmK0JVzSKWhGjTMFlpckTHgMwWiSrmnFc1ijVp8XRmLbYubM+VPK8buHMqPFX2ZZ36TEr+K7ObdaQO9RfvW9RX7RTfnkWvtHIMBGFBXDvXkGAAoiKjPDvWf+Xb1vsoCzk5ztnwK/kQR56SszEGBWGDHdCsVhk+QeG5JKFVqlqf3yxDEviv6LdWdWSt2TeMouMoJsAEnLpIei4wRYWAaxTpUDNwHA3/TsdIwYpg7JPx7sH3XFnrZSJAHE3ue/Fx8Yv1U5xd7mI= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:BL3PR11MB6434.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230022)(39860400002)(136003)(346002)(396003)(376002)(366004)(451199015)(5660300002)(52536014)(86362001)(41300700001)(33656002)(8936002)(2906002)(83380400001)(9686003)(82960400001)(122000001)(38100700002)(26005)(30864003)(4326008)(54906003)(110136005)(19627235002)(7696005)(186003)(45080400002)(8676002)(66476007)(64756008)(76116006)(66556008)(66946007)(316002)(6506007)(66446008)(107886003)(53546011)(966005)(38070700005)(478600001)(71200400001)(66899015)(55016003)(579004)(559001)(44824005)(14943795004);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?fe4ezIPV9UDui9nU+0EoOABXo+n8TB0eMUnsrlWaJe3tEqWhjk60/qhLHVBy?= =?us-ascii?Q?RZ1xeo7dWkVjw1dFLUZ2O4z+pCn9HtkYCCDGEZOHx/fApFTGgJcbi4Ji3bUL?= =?us-ascii?Q?WcEXMCSrm/Y4Ak/h4KOPAaIIiibztWihZGN32irVTLeV7PgQtg3v+Eb047VS?= =?us-ascii?Q?uG+EFrAwc6JryjxkwDFNGc8MdTaSiTY+h45PKeVvZJFhkw9wRreO3wqQsHxG?= =?us-ascii?Q?PF/sjpi8fN5b6F42DW7IlY/6GUgxaI/G/vBXGnUklV/0PSoeydFZItG2aUXT?= =?us-ascii?Q?5jrC/dJ/fxRsk2bgEiU4sD7DXgYWDhpe2hPqEteSEHhgABfHlneiefyj52pG?= =?us-ascii?Q?mj3ng7uuf1BVpT1zgJTAjYhJbMjsQ+UmsTh5007nKoGq+WrOPqgqJJ9KakNn?= =?us-ascii?Q?blILTkWLmxmjpWsCOF6/EapjtF2nP9cFuBEeOoS7/lxV99bg8pQDPMxxzmZx?= =?us-ascii?Q?p7foYPLickCHnBG84ZxFeT80bQgM6RWQlvkR8keo4ytkFycKa2ZK2uErhTlJ?= =?us-ascii?Q?o9NMz+WGtCm1vWqHY3cXTWh0xy72hyZFo5NzFcnjf9WHvm77CsOykI0viJDr?= =?us-ascii?Q?XOAX0U3HFqp2OrPMrk2t82yQcxUKxEcsCqDy52C/NSDtQD5cF2AIBRJonnNx?= =?us-ascii?Q?Wxyfg8xgewBOc/CMC3wNttd7P2hlz6ycH5hUM2kfD7gni3kULyfzt9ODE4TJ?= =?us-ascii?Q?3guj0sbDhS8Icf2Q+PtD78qEBcVdH9QNhHZ+vGbSR75lXc6rOZj7FEv0bkqv?= =?us-ascii?Q?XGnhWGmIMKgtNO5kcs+fYuGHBqoCxPJnKkega0Y2vf41dIjvk0DezrbTWLmF?= =?us-ascii?Q?JBDSqyBRupD/VSHA2hkYN0lAeoNhIUsYZFy5zz8CPQhoRO2kTCDr1Qv9+7KQ?= =?us-ascii?Q?x3fDdL/MuGXycr8yhKutAIWnu+lKe7DhLkjMIBq/16DyZQlkXhPNZEezySU0?= =?us-ascii?Q?s6Jh6pNcE079hfQHFtJUH5TWcud461tBSX+k5iQXt2cE+UmOzO/fmztS2OTi?= =?us-ascii?Q?AhTDdL6qN1YOT1pWSGfKCvGzhbv+LZjqelEJr8WHV1chTSgKF5RH0sTqDvig?= =?us-ascii?Q?hXQ8dDbUn501UOjanuGDwfLF5tdEuNA4jWernuBoOxxY2Q5orsc2Bnwj4TJF?= =?us-ascii?Q?1dFJ+hKDygMIAzsOPt/f0cHYz2CUwPymhoBSuFU3kXzekpEzbvNCDVdrwuW+?= =?us-ascii?Q?b6TwsdbyOftJ9AoZihqX9O9+oM1glgYGIOalqj2iUtyts0riFMRcFvsn7Gc7?= =?us-ascii?Q?7dhklDvi4Qruc5xe8l0xg2YM6j44Jrak4YFdoyI5rerD/LAoshbuKBWj2au3?= =?us-ascii?Q?C+ogYtub2xjN4Z1Q85jD+NVfeVEXSXyfIsreFMCPoykpcBEz1mmtgIeUTe7e?= =?us-ascii?Q?Je0qpsuDtmCvLDyE2zj69zuBGeCsZDknk28uiCvYUXV/Rv+UBpJSJAwxHq+7?= =?us-ascii?Q?pG4g3IGbRfp/xYPe1HDf8k6rUcy4OFM4Y5wsOGhladY30arxa+SbjNa5+6HA?= =?us-ascii?Q?4NLrATgVehTAN2wS1m8WT/oVux78jDA0us2XurCLYtpiyQdbjkH3DEBsMjSw?= =?us-ascii?Q?i5bUs7tVz9irjK6yMacWAm9wvcudTLyuUWdWD9hN?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: BL3PR11MB6434.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: f1a7c5f6-4dd8-4115-5211-08dac6645b37 X-MS-Exchange-CrossTenant-originalarrivaltime: 14 Nov 2022 17:19:15.5103 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: GScbF6QZ3uz79/Eo510sApt0WqyjYR8vuysxcQaClxsa0sIZQmZNVwcDMPiILaU/VcU+tGb+ONWhHs9K2MMItQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR11MB4561 Return-Path: judah.vang@intel.com X-OriginatorOrg: intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Jian, That's not the reason why I removed the leading '_' underscore. When I don't remove it, the EDK2 CI is giving me a fail and telling me it n= eeds to be removed. I don't know why this is the case but it seems to only happen for new files= . Judah -----Original Message----- From: Wang, Jian J =20 Sent: Sunday, November 13, 2022 11:14 PM To: Vang, Judah ; devel@edk2.groups.io Cc: Gao, Liming ; Wu, Hao A ;= Mistry, Nishant C Subject: RE: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Varia= bles Hi Judah, Just one comment: For all header files, no need to remove the opening '_' of include guard ma= cro. Protected variable code are now in different folder than original variable = driver. They won't reference code from each other. Please add the opening '_' for t= hose macros to confirm to edk2 coding convention. Regards, Jian > -----Original Message----- > From: Vang, Judah > Sent: Sunday, November 06, 2022 3:35 PM > To: devel@edk2.groups.io > Cc: Wang, Jian J ; Gao, Liming > ; Wu, Hao A ; Mistry, > Nishant C > Subject: [PATCH v5 08/19] MdeModulePkg: Add support for Protected Variabl= es >=20 > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2594 >=20 > V5: Add RuntimeDxe Variable Protection into a new directory and > keep existing Variable for RuntimeDxe unchanged. >=20 > v4: Applied code review - remove unreferenced library from .inf. > Updated some function description and parameters. >=20 > V3: Fix 'NextVariableStore' parameter for CopyMem. It was causing > an exception. Need to correctly cast 'NextVariableStore' so all > platforms build. Add code to initialize 'ContextIn' structure in > SmmVariableReay() to fix issue with NULL function pointer. >=20 > V1: Add support for Protected Variables. > Add new API to retrieve Variable Infomation and data. > Add new API to update variable in non-volatile storage or > cached copy. >=20 > Cc: Jian J Wang > Cc: Liming Gao > Cc: Hao A Wu > Cc: Nishant C Mistry > Signed-off-by: Jian J Wang > Signed-off-by: Nishant C Mistry > Signed-off-by: Judah Vang > --- >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes > t/VariableLockRequestToLockUnitTest.inf | 36 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe > .inf | 151 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf > | 153 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim > eDxe.inf | 119 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone > Mm.inf | 143 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorphi > c.h | 158 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h > | 948 +++++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile > .h | 67 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h > | 424 ++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac > he.h | 51 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c > | 343 ++ > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c > | 504 +++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitTes > t/VariableLockRequestToLockUnitTest.c | 607 +++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierD > xe.c | 27 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrierS > mm.c | 26 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c > | 153 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm.c > | 569 +++ > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c > | 101 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c > | 4037 ++++++++++++++++++++ > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c > | 670 ++++ > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c > | 417 ++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockReques > tToLock.c | 96 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolatile > .c | 537 +++ > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c > | 1110 ++++++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySmm > Dxe.c | 575 +++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeCac > he.c | 158 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c > | 1268 ++++++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim > eDxe.c | 1895 +++++++++ >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalone > Mm.c | 89 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTraditional > Mm.c | 130 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe > .uni | 22 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeDxe > Extra.uni | 14 + > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni > | 27 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtra.u > ni | 14 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim > eDxe.uni | 23 + >=20 > MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRuntim > eDxeExtra.uni | 14 + > 36 files changed, 15676 insertions(+) >=20 > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.inf > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.inf > new file mode 100644 > index 000000000000..586d877fca90 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.inf > @@ -0,0 +1,36 @@ > +## @file > +# This is a host-based unit test for the VariableLockRequestToLock shim. > +# > +# Copyright (c) Microsoft Corporation. > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +## > + > +[Defines] > + INF_VERSION =3D 0x00010017 > + BASE_NAME =3D VariableLockRequestToLockUnitTest > + FILE_GUID =3D A657FCD8-4A0D-46B4-8DC9-F089626383AD > + VERSION_STRING =3D 1.0 > + MODULE_TYPE =3D HOST_APPLICATION > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64 > +# > + > +[Sources] > + VariableLockRequestToLockUnitTest.c > + ../VariableLockRequestToLock.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec > + > +[LibraryClasses] > + UnitTestLib > + DebugLib > + VariablePolicyLib > + VariablePolicyHelperLib > + BaseMemoryLib > + MemoryAllocationLib > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.inf > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.inf > new file mode 100644 > index 000000000000..6adc2c636e84 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.inf > @@ -0,0 +1,151 @@ > +## @file > +# Provides variable service. > +# > +# This module installs variable arch protocol and variable write arch p= rotocol > to provide > +# variable services: SetVariable, GetVariable, GetNextVariableName and > QueryVariableInfo. > +# > +# Caution: This module requires additional review when modified. > +# This driver will have external input - variable data. > +# This external input must be validated carefully to avoid security iss= ues such > as > +# buffer overflow or integer overflow. > +# > +# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +# Copyright (c) Microsoft Corporation. > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D VariableRuntimeDxe > + MODULE_UNI_FILE =3D VariableRuntimeDxe.uni > + FILE_GUID =3D 146F4448-56BF-405C-A8C4-B77FFD24BE0= 0 > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D VariableServiceInitialize > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 EBC > +# > +# VIRTUAL_ADDRESS_MAP_CALLBACK =3D VariableClassAddressChangeEvent > +# > + > +[Sources] > + Reclaim.c > + Variable.c > + VariableDxe.c > + Variable.h > + VariableNonVolatile.c > + VariableNonVolatile.h > + VariableParsing.c > + VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > + PrivilegePolymorphic.h > + Measurement.c > + TcgMorLockDxe.c > + VarCheck.c > + VariableExLib.c > + SpeculationBarrierDxe.c > + VariableLockRequestToLock.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + MemoryAllocationLib > + BaseLib > + SynchronizationLib > + UefiLib > + UefiBootServicesTableLib > + BaseMemoryLib > + DebugLib > + UefiRuntimeLib > + DxeServicesTableLib > + UefiDriverEntryPoint > + PcdLib > + HobLib > + TpmMeasurementLib > + AuthVariableLib > + VarCheckLib > + VariableFlashInfoLib > + VariablePolicyLib > + VariablePolicyHelperLib > + SafeIntLib > + ProtectedVariableLib > + > +[Protocols] > + gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES > + ## CONSUMES > + ## NOTIFY > + gEfiFaultTolerantWriteProtocolGuid > + gEfiVariableWriteArchProtocolGuid ## PRODUCES > + gEfiVariableArchProtocolGuid ## PRODUCES > + gEdkiiVariableLockProtocolGuid ## PRODUCES > + gEdkiiVariablePolicyProtocolGuid ## CONSUMES > + gEdkiiVarCheckProtocolGuid ## PRODUCES > + > +[Guids] > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiAuthenticatedVariableGuid > + > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiVariableGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" > + ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" > + ## SOMETIMES_CONSUMES ## Variable:L"Lang" > + ## SOMETIMES_PRODUCES ## Variable:L"Lang" > + ## SOMETIMES_CONSUMES ## Variable:L"PK" > + ## SOMETIMES_CONSUMES ## Variable:L"KEK" > + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" > + gEfiGlobalVariableGuid > + > + gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES = ## > Variable:L"MemoryOverwriteRequestControl" > + gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES > ## Variable:L"MemoryOverwriteRequestControlLock" > + > + gEfiEventVirtualAddressChangeGuid ## CONSUMES = ## Event > + gEfiSystemNvDataFvGuid ## CONSUMES = ## GUID > + gEfiEndOfDxeEventGroupGuid ## CONSUMES = ## Event > + gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES = ## HOB > + > + ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag" > + ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag" > + gEdkiiVarErrorFlagGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"db" > + ## SOMETIMES_CONSUMES ## Variable:L"dbx" > + ## SOMETIMES_CONSUMES ## Variable:L"dbt" > + gEfiImageSecurityDatabaseGuid > + > +[Pcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize > ## CONSUMES > + > gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## > SOMETIMES_CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## > SOMETIMES_CONSUMES > + > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## > CONSUMES # statistic the information of variable. > + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## > CONSUMES # Auto update PlatformLang/Lang > + > +[Depex] > + TRUE > + > +[UserExtensions.TianoCore."ExtraFiles"] > + VariableRuntimeDxeExtra.uni > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf > new file mode 100644 > index 000000000000..2651ec514df3 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.inf > @@ -0,0 +1,153 @@ > +## @file > +# Provides SMM variable service. > +# > +# This module installs SMM variable protocol into SMM protocol database= , > +# which can be used by SMM driver, and installs SMM variable protocol > +# into BS protocol database, which can be used to notify the SMM Runtim= e > +# Dxe driver that the SMM variable service is ready. > +# This module should be used with SMM Runtime DXE module together. The > +# SMM Runtime DXE module would install variable arch protocol and varia= ble > +# write arch protocol based on SMM variable module. > +# > +# Caution: This module requires additional review when modified. > +# This driver will have external input - variable data and communicate = buffer in > SMM mode. > +# This external input must be validated carefully to avoid security iss= ues such > as > +# buffer overflow or integer overflow. > +# The whole SMM authentication variable design relies on the integrit= y of > flash part and SMM. > +# which is assumed to be protected by platform. All variable code and > metadata in flash/SMM Memory > +# may not be modified without authorization. If platform fails to prote= ct these > resources, > +# the authentication service provided in this driver will be broken, an= d the > behavior is undefined. > +# > +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> +# Copyright (c) Microsoft Corporation. > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D VariableSmm > + MODULE_UNI_FILE =3D VariableSmm.uni > + FILE_GUID =3D 1C32FDDF-7FF1-4EE5-BDA0-ED9AAC623D3= C > + MODULE_TYPE =3D DXE_SMM_DRIVER > + VERSION_STRING =3D 1.0 > + PI_SPECIFICATION_VERSION =3D 0x0001000A > + ENTRY_POINT =3D VariableServiceInitialize > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > + > + > +[Sources] > + Reclaim.c > + Variable.c > + VariableTraditionalMm.c > + VariableSmm.c > + VariableNonVolatile.c > + VariableNonVolatile.h > + VariableParsing.c > + VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > + VarCheck.c > + Variable.h > + PrivilegePolymorphic.h > + VariableExLib.c > + TcgMorLockSmm.c > + SpeculationBarrierSmm.c > + VariableLockRequestToLock.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + UefiDriverEntryPoint > + MemoryAllocationLib > + BaseLib > + SynchronizationLib > + UefiLib > + MmServicesTableLib > + BaseMemoryLib > + DebugLib > + DxeServicesTableLib > + HobLib > + PcdLib > + SmmMemLib > + AuthVariableLib > + VarCheckLib > + UefiBootServicesTableLib > + VariableFlashInfoLib > + VariablePolicyLib > + VariablePolicyHelperLib > + SafeIntLib > + ProtectedVariableLib > + > +[Protocols] > + gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES > + ## CONSUMES > + ## NOTIFY > + gEfiSmmFaultTolerantWriteProtocolGuid > + ## PRODUCES > + ## UNDEFINED # SmiHandlerRegister > + gEfiSmmVariableProtocolGuid > + gEfiMmEndOfDxeProtocolGuid ## NOTIFY > + gEdkiiSmmVarCheckProtocolGuid ## PRODUCES > + gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES > + gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES > + > +[Guids] > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiAuthenticatedVariableGuid > + > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiVariableGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" > + ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" > + ## SOMETIMES_CONSUMES ## Variable:L"Lang" > + ## SOMETIMES_PRODUCES ## Variable:L"Lang" > + gEfiGlobalVariableGuid > + > + gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES = ## > Variable:L"MemoryOverwriteRequestControl" > + gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES > ## Variable:L"MemoryOverwriteRequestControlLock" > + > + gSmmVariableWriteGuid ## PRODUCES = ## GUID # Install > protocol > + gEfiSystemNvDataFvGuid ## CONSUMES = ## GUID > + gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES = ## HOB > + > + ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag" > + ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag" > + gEdkiiVarErrorFlagGuid > + > +[Pcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize > ## CONSUMES > + > gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## > SOMETIMES_CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## > SOMETIMES_CONSUMES > + > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## > CONSUMES # statistic the information of variable. > + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## > CONSUMES # Auto update PlatformLang/Lang > + > +[Depex] > + TRUE > + > +[UserExtensions.TianoCore."ExtraFiles"] > + VariableSmmExtra.uni > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.inf > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.inf > new file mode 100644 > index 000000000000..0d169913c9c9 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.inf > @@ -0,0 +1,119 @@ > +## @file > +# Runtime DXE part corresponding to SMM authenticated variable module. > +# > +# This module installs variable arch protocol and variable write arch p= rotocol > to provide > +# variable service. This module need work together with SMM authenticat= ed > variable module. > +# > +# Caution: This module requires additional review when modified. > +# This driver will have external input - variable data. > +# This external input must be validated carefully to avoid security iss= ues such > as > +# buffer overflow or integer overflow. > +# The whole SMM authentication variable design relies on the integrit= y of > flash part and SMM. > +# which is assumed to be protected by platform. All variable code and > metadata in flash/SMM Memory > +# may not be modified without authorization. If platform fails to prote= ct these > resources, > +# the authentication service provided in this driver will be broken, an= d the > behavior is undefined. > +# > +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> +# Copyright (c) Microsoft Corporation.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D VariableSmmRuntimeDxe > + MODULE_UNI_FILE =3D VariableSmmRuntimeDxe.uni > + FILE_GUID =3D 3C9DF4B3-559F-4AE4-AEA3-E4B0C3D9D3E= E > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D VariableSmmRuntimeInitialize > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > +# VIRTUAL_ADDRESS_MAP_CALLBACK =3D VariableAddressChangeEvent > +# > + > +[Sources] > + VariableSmmRuntimeDxe.c > + PrivilegePolymorphic.h > + Measurement.c > + VariableParsing.c > + VariableParsing.h > + Variable.h > + VariablePolicySmmDxe.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + MemoryAllocationLib > + BaseLib > + UefiBootServicesTableLib > + DebugLib > + UefiRuntimeLib > + DxeServicesTableLib > + UefiDriverEntryPoint > + TpmMeasurementLib > + SafeIntLib > + PcdLib > + MmUnblockMemoryLib > + ProtectedVariableLib > + > +[Protocols] > + gEfiVariableWriteArchProtocolGuid ## PRODUCES > + gEfiVariableArchProtocolGuid ## PRODUCES > + gEfiMmCommunication2ProtocolGuid ## CONSUMES > + ## CONSUMES > + ## NOTIFY > + ## UNDEFINED # Used to do smm communication > + gEfiSmmVariableProtocolGuid > + gEdkiiVariableLockProtocolGuid ## PRODUCES > + gEdkiiVarCheckProtocolGuid ## PRODUCES > + gEdkiiVariablePolicyProtocolGuid ## PRODUCES > + > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics = ## > CONSUMES > + > +[Pcd] > + > gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable > ## CONSUMES > + > +[Guids] > + ## PRODUCES ## GUID # Signature of Variable store header > + ## CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiAuthenticatedVariableGuid > + > + ## PRODUCES ## GUID # Signature of Variable store header > + ## CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiVariableGuid > + > + gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event > + gEfiEventExitBootServicesGuid ## CONSUMES ## Event > + ## CONSUMES ## GUID # Locate protocol > + ## CONSUMES ## GUID # Protocol notify > + gSmmVariableWriteGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"PK" > + ## SOMETIMES_CONSUMES ## Variable:L"KEK" > + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" > + gEfiGlobalVariableGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"db" > + ## SOMETIMES_CONSUMES ## Variable:L"dbx" > + ## SOMETIMES_CONSUMES ## Variable:L"dbt" > + gEfiImageSecurityDatabaseGuid > + > + gVarCheckPolicyLibMmiHandlerGuid > + gEfiEndOfDxeEventGroupGuid > + > +[Depex] > + gEfiMmCommunication2ProtocolGuid > + > +[UserExtensions.TianoCore."ExtraFiles"] > + VariableSmmRuntimeDxeExtra.uni > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.inf > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.inf > new file mode 100644 > index 000000000000..fb5a6c947890 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.inf > @@ -0,0 +1,143 @@ > +## @file > +# Provides SMM variable service. > +# > +# This module installs SMM variable protocol into SMM protocol database= , > +# which can be used by SMM driver, and installs SMM variable protocol > +# into BS protocol database, which can be used to notify the SMM Runtim= e > +# Dxe driver that the SMM variable service is ready. > +# This module should be used with SMM Runtime DXE module together. The > +# SMM Runtime DXE module would install variable arch protocol and varia= ble > +# write arch protocol based on SMM variable module. > +# > +# Caution: This module requires additional review when modified. > +# This driver will have external input - variable data and communicate = buffer in > SMM mode. > +# This external input must be validated carefully to avoid security iss= ues such > as > +# buffer overflow or integer overflow. > +# The whole SMM authentication variable design relies on the integrit= y of > flash part and SMM. > +# which is assumed to be protected by platform. All variable code and > metadata in flash/SMM Memory > +# may not be modified without authorization. If platform fails to prote= ct these > resources, > +# the authentication service provided in this driver will be broken, an= d the > behavior is undefined. > +# > +# Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
> +# Copyright (c) Microsoft Corporation. > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x0001001B > + BASE_NAME =3D VariableStandaloneMm > + FILE_GUID =3D 417E6192-7678-4A75-B638-305A86D8293= 6 > + MODULE_TYPE =3D MM_STANDALONE > + VERSION_STRING =3D 1.0 > + PI_SPECIFICATION_VERSION =3D 0x00010032 > + ENTRY_POINT =3D VariableServiceInitialize > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64 > +# > + > + > +[Sources] > + Reclaim.c > + Variable.c > + VariableSmm.c > + VariableStandaloneMm.c > + VariableNonVolatile.c > + VariableNonVolatile.h > + VariableParsing.c > + VariableParsing.h > + VariableRuntimeCache.c > + VariableRuntimeCache.h > + VarCheck.c > + Variable.h > + PrivilegePolymorphic.h > + VariableExLib.c > + TcgMorLockSmm.c > + SpeculationBarrierSmm.c > + VariableLockRequestToLock.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + StandaloneMmPkg/StandaloneMmPkg.dec > + > +[LibraryClasses] > + AuthVariableLib > + BaseLib > + BaseMemoryLib > + DebugLib > + HobLib > + MemoryAllocationLib > + MmServicesTableLib > + SafeIntLib > + StandaloneMmDriverEntryPoint > + SynchronizationLib > + VarCheckLib > + VariableFlashInfoLib > + VariablePolicyLib > + VariablePolicyHelperLib > + ProtectedVariableLib > + > +[Protocols] > + gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES > + ## CONSUMES > + ## NOTIFY > + gEfiSmmFaultTolerantWriteProtocolGuid > + ## PRODUCES > + ## UNDEFINED # SmiHandlerRegister > + gEfiSmmVariableProtocolGuid > + gEfiMmEndOfDxeProtocolGuid ## NOTIFY > + gEdkiiSmmVarCheckProtocolGuid ## PRODUCES > + > +[Guids] > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiAuthenticatedVariableGuid > + > + ## SOMETIMES_CONSUMES ## GUID # Signature of Variable store header > + ## SOMETIMES_PRODUCES ## GUID # Signature of Variable store header > + ## SOMETIMES_CONSUMES ## HOB > + ## SOMETIMES_PRODUCES ## SystemTable > + gEfiVariableGuid > + > + ## SOMETIMES_CONSUMES ## Variable:L"PlatformLang" > + ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" > + ## SOMETIMES_CONSUMES ## Variable:L"Lang" > + ## SOMETIMES_PRODUCES ## Variable:L"Lang" > + gEfiGlobalVariableGuid > + > + gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES = ## > Variable:L"MemoryOverwriteRequestControl" > + gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES > ## Variable:L"MemoryOverwriteRequestControlLock" > + > + gEfiSystemNvDataFvGuid ## CONSUMES = ## GUID > + gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES = ## HOB > + > + ## SOMETIMES_CONSUMES ## Variable:L"VarErrorFlag" > + ## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag" > + gEdkiiVarErrorFlagGuid > + > +[Pcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## > CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize > ## CONSUMES > + > gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe > ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## > SOMETIMES_CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## > SOMETIMES_CONSUMES > + > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## > CONSUMES # statistic the information of variable. > + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## > CONSUMES # Auto update PlatformLang/Lang > + > +[Depex] > + TRUE > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp > hic.h > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp > hic.h > new file mode 100644 > index 000000000000..7f14515b694f > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/PrivilegePolymorp > hic.h > @@ -0,0 +1,158 @@ > +/** @file > + Polymorphic functions that are called from both the privileged driver = (i.e., > + the DXE_SMM variable module) and the non-privileged drivers (i.e., one= or > + both of the DXE_RUNTIME variable modules). > + > + Each of these functions has two implementations, appropriate for privi= leged > + vs. non-privileged driver code. > + > + Copyright (c) 2017, Red Hat, Inc.
> + Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef PRIVILEGE_POLYMORPHIC_H_ > +#define PRIVILEGE_POLYMORPHIC_H_ > + > +#include > + > +/** > + SecureBoot Hook for auth variable update. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > +**/ > +VOID > +EFIAPI > +SecureBootHook ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ); > + > +/** > + Initialization for MOR Control Lock. > + > + @retval EFI_SUCCESS MorLock initialization success. > + @return Others Some error occurs. > +**/ > +EFI_STATUS > +MorLockInit ( > + VOID > + ); > + > +/** > + Delayed initialization for MOR Control Lock at EndOfDxe. > + > + This function performs any operations queued by MorLockInit(). > +**/ > +VOID > +MorLockInitAtEndOfDxe ( > + VOID > + ); > + > +/** > + This service is an MOR/MorLock checker handler for the SetVariable(). > + > + @param[in] VariableName the name of the vendor's variable, as a > + Null-Terminated Unicode String > + @param[in] VendorGuid Unify identifier for vendor. > + @param[in] Attributes Attributes bitmask to set for the variable. > + @param[in] DataSize The size in bytes of Data-Buffer. > + @param[in] Data Point to the content of the variable. > + > + @retval EFI_SUCCESS The MOR/MorLock check pass, and Variab= le > + driver can store the variable data. > + @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or > + attributes is not allowed for MOR vari= able. > + @retval EFI_ACCESS_DENIED The MOR/MorLock is locked. > + @retval EFI_ALREADY_STARTED The MorLock variable is handled inside= this > + function. Variable driver can just ret= urn > + EFI_SUCCESS. > +**/ > +EFI_STATUS > +SetVariableCheckHandlerMor ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ); > + > +/** > + This service is consumed by the variable modules to place a barrier to= stop > + speculative execution. > + > + Ensures that no later instruction will execute speculatively, until al= l prior > + instructions have completed. > + > +**/ > +VOID > +VariableSpeculationBarrier ( > + VOID > + ); > + > +/** > + Notify the system that the SMM variable driver is ready. > +**/ > +VOID > +VariableNotifySmmReady ( > + VOID > + ); > + > +/** > + Notify the system that the SMM variable write driver is ready. > +**/ > +VOID > +VariableNotifySmmWriteReady ( > + VOID > + ); > + > +/** > + Variable Driver main entry point. The Variable driver places the 4 EFI > + runtime services in the EFI System Table and installs arch protocols > + for variable read and write services being available. It also register= s > + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE > event. > + > + @retval EFI_SUCCESS Variable service successfully initialized. > +**/ > +EFI_STATUS > +EFIAPI > +MmVariableServiceInitialize ( > + VOID > + ); > + > +/** > + This function checks if the buffer is valid per processor architecture= and > + does not overlap with SMRAM. > + > + @param Buffer The buffer start address to be checked. > + @param Length The buffer length to be checked. > + > + @retval TRUE This buffer is valid per processor architecture and does= not > + overlap with SMRAM. > + @retval FALSE This buffer is not valid per processor architecture or o= verlaps > + with SMRAM. > +**/ > +BOOLEAN > +VariableSmmIsBufferOutsideSmmValid ( > + IN EFI_PHYSICAL_ADDRESS Buffer, > + IN UINT64 Length > + ); > + > +/** > + Whether the TCG or TCG2 protocols are installed in the UEFI protocol > database. > + This information is used by the MorLock code to infer whether an exist= ing > + MOR variable is legitimate or not. > + > + @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI > + protocol database > + @retval FALSE Neither the TCG nor the TCG2 protocol is installed in th= e UEFI > + protocol database > +**/ > +BOOLEAN > +VariableHaveTcgProtocols ( > + VOID > + ); > + > +#endif > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h > new file mode 100644 > index 000000000000..c679e524043f > --- /dev/null > +++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.h > @@ -0,0 +1,948 @@ > +/** @file > + The internal header file includes the common header files, defines > + internal structure and functions used by Variable modules. > + > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef VARIABLE_H_ > +#define VARIABLE_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "PrivilegePolymorphic.h" > + > +#define EFI_VARIABLE_ATTRIBUTES_MASK (EFI_VARIABLE_NON_VOLATILE |\ > + EFI_VARIABLE_BOOTSERVICE_ACCESS | = \ > + EFI_VARIABLE_RUNTIME_ACCESS | \ > + EFI_VARIABLE_HARDWARE_ERROR_RECORD= | \ > + > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ > + EFI_VARIABLE_APPEND_WRITE) > + > +/// > +/// The size of a 3 character ISO639 language code. > +/// > +#define ISO_639_2_ENTRY_SIZE 3 > + > +typedef enum { > + VariableStoreTypeVolatile, > + VariableStoreTypeHob, > + VariableStoreTypeNv, > + VariableStoreTypeMax > +} VARIABLE_STORE_TYPE; > + > +typedef struct { > + UINT32 PendingUpdateOffset; > + UINT32 PendingUpdateLength; > + VARIABLE_STORE_HEADER *Store; > +} VARIABLE_RUNTIME_CACHE; > + > +typedef struct { > + BOOLEAN *ReadLock; > + BOOLEAN *PendingUpdate; > + BOOLEAN *HobFlushComplete; > + VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache; > + VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache; > + VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache; > +} VARIABLE_RUNTIME_CACHE_CONTEXT; > + > +typedef struct { > + VARIABLE_HEADER *CurrPtr; > + // > + // If both ADDED and IN_DELETED_TRANSITION variable are present, > + // InDeletedTransitionPtr will point to the IN_DELETED_TRANSITION one. > + // Otherwise, CurrPtr will point to the ADDED or IN_DELETED_TRANSITION > one, > + // and InDeletedTransitionPtr will be NULL at the same time. > + // > + VARIABLE_HEADER *InDeletedTransitionPtr; > + VARIABLE_HEADER *EndPtr; > + VARIABLE_HEADER *StartPtr; > + BOOLEAN Volatile; > +} VARIABLE_POINTER_TRACK; > + > +typedef struct { > + EFI_PHYSICAL_ADDRESS HobVariableBase; > + EFI_PHYSICAL_ADDRESS VolatileVariableBase; > + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; > + VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext; > + EFI_LOCK VariableServicesLock; > + UINT32 ReentrantState; > + BOOLEAN AuthFormat; > + BOOLEAN AuthSupport; > + BOOLEAN EmuNvMode; > +} VARIABLE_GLOBAL; > + > +typedef struct { > + VARIABLE_GLOBAL VariableGlobal; > + UINTN VolatileLastVariableOffset; > + UINTN NonVolatileLastVariableOffset; > + UINTN CommonVariableSpace; > + UINTN CommonMaxUserVariableSpace; > + UINTN CommonRuntimeVariableSpace; > + UINTN CommonVariableTotalSize; > + UINTN CommonUserVariableTotalSize; > + UINTN HwErrVariableTotalSize; > + UINTN MaxVariableSize; > + UINTN MaxAuthVariableSize; > + UINTN MaxVolatileVariableSize; > + UINTN ScratchBufferSize; > + CHAR8 *PlatformLangCodes; > + CHAR8 *LangCodes; > + CHAR8 *PlatformLang; > + CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1]; > + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance; > +} VARIABLE_MODULE_GLOBAL; > + > +/** > + Flush the HOB variable to flash. > + > + @param[in] VariableName Name of variable has been updated or del= eted. > + @param[in] VendorGuid Guid of variable has been updated or del= eted. > + > +**/ > +VOID > +FlushHobVariableToFlash ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ); > + > +/** > + Writes a buffer to variable storage space, in the working block. > + > + This function writes a buffer to variable storage space into a firmwar= e > + volume block device. The destination is specified by the parameter > + VariableBase. Fault Tolerant Write protocol is used for writing. > + > + @param VariableBase Base address of the variable to write. > + @param VariableBuffer Point to the variable data buffer. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. > + @retval EFI_ABORTED The function could not complete successfully. > + > +**/ > +EFI_STATUS > +FtwVariableSpace ( > + IN EFI_PHYSICAL_ADDRESS VariableBase, > + IN VARIABLE_STORE_HEADER *VariableBuffer > + ); > + > +/** > + Finds variable in storage blocks of volatile and non-volatile storage = areas. > + > + This code finds variable in storage blocks of volatile and non-volatil= e storage > areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + If IgnoreRtCheck is TRUE, then we ignore the > EFI_VARIABLE_RUNTIME_ACCESS attribute check > + at runtime when searching existing variable, only VariableName and > VendorGuid are compared. > + Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visib= le > at runtime. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Vendor GUID to be found. > + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure f= or > output, > + including the range searched and t= he target position. > + @param[in] Global Pointer to VARIABLE_GLOBAL structu= re, > including > + base of volatile variable storage = area, base of > + NV variable storage area, and a lo= ck. > + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS > attribute > + check at runtime when searching va= riable. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty st= ring, > while > + VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +FindVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT VARIABLE_POINTER_TRACK *PtrTrack, > + IN VARIABLE_GLOBAL *Global, > + IN BOOLEAN IgnoreRtCheck > + ); > + > +/** > + This function is to check if the remaining variable space is enough to= set > + all Variables from argument list successfully. The purpose of the chec= k > + is to keep the consistency of the Variables to be in variable storage. > + > + Note: Variables are assumed to be in same storage. > + The set sequence of Variables will be same with the sequence of Variab= leEntry > from argument list, > + so follow the argument sequence to check the Variables. > + > + @param[in] Attributes Variable attributes for Variable entries= . > + @param[in] Marker VA_LIST style variable argument list. > + The variable argument list with type > VARIABLE_ENTRY_CONSISTENCY *. > + A NULL terminates the list. The Variable= Size of > + VARIABLE_ENTRY_CONSISTENCY is the variab= le data size as > input. > + It will be changed to variable total siz= e as output. > + > + @retval TRUE Have enough variable space to set the Va= riables > successfully. > + @retval FALSE No enough variable space to set the Vari= ables > successfully. > + > +**/ > +BOOLEAN > +EFIAPI > +CheckRemainingSpaceForConsistencyInternal ( > + IN UINT32 Attributes, > + IN VA_LIST Marker > + ); > + > +/** > + Update the variable region with Variable information. If > EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set, > + index of associated public key is needed. > + > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Data Variable data. > + @param[in] DataSize Size of data. 0 means delete. > + @param[in] Attributes Attributes of the variable. > + @param[in] KeyIndex Index of associated public key. > + @param[in] MonotonicCount Value of associated monotonic count. > + @param[in, out] Variable The variable information that is used to= keep > track of variable usage. > + > + @param[in] TimeStamp Value of associated TimeStamp. > + > + @retval EFI_SUCCESS The update operation is success. > + @retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write ot= her > data into this region. > + > +**/ > +EFI_STATUS > +UpdateVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VOID *Data, > + IN UINTN DataSize, > + IN UINT32 Attributes OPTIONAL, > + IN UINT32 KeyIndex OPTIONAL, > + IN UINT64 MonotonicCount OPTIONAL, > + IN OUT VARIABLE_POINTER_TRACK *Variable, > + IN EFI_TIME *TimeStamp OPTIONAL > + ); > + > +/** > + Return TRUE if ExitBootServices () has been called. > + > + @retval TRUE If ExitBootServices () has been called. > +**/ > +BOOLEAN > +AtRuntime ( > + VOID > + ); > + > +/** > + Initializes a basic mutual exclusion lock. > + > + This function initializes a basic mutual exclusion lock to the release= d state > + and returns the lock. Each lock provides mutual exclusion access at i= ts task > + priority level. Since there is no preemption or multiprocessor suppor= t in EFI, > + acquiring the lock only consists of raising to the locks TPL. > + If Lock is NULL, then ASSERT(). > + If Priority is not a valid TPL value, then ASSERT(). > + > + @param Lock A pointer to the lock data structure to initialize. > + @param Priority EFI TPL is associated with the lock. > + > + @return The lock. > + > +**/ > +EFI_LOCK * > +InitializeLock ( > + IN OUT EFI_LOCK *Lock, > + IN EFI_TPL Priority > + ); > + > +/** > + Acquires lock only at boot time. Simply returns at runtime. > + > + This is a temperary function that will be removed when > + EfiAcquireLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiAcquireLock() at boot time, and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to acquire. > + > +**/ > +VOID > +AcquireLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ); > + > +/** > + Releases lock only at boot time. Simply returns at runtime. > + > + This is a temperary function which will be removed when > + EfiReleaseLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiReleaseLock() at boot time and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to release. > + > +**/ > +VOID > +ReleaseLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ); > + > +/** > + Retrieve the FVB protocol interface by HANDLE. > + > + @param[in] FvBlockHandle The handle of FVB protocol that provides > services for > + reading, writing, and erasing the target= block. > + @param[out] FvBlock The interface of FVB protocol > + > + @retval EFI_SUCCESS The interface information for the specif= ied > protocol was returned. > + @retval EFI_UNSUPPORTED The device does not support the FVB prot= ocol. > + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE > or FvBlock is NULL. > + > +**/ > +EFI_STATUS > +GetFvbByHandle ( > + IN EFI_HANDLE FvBlockHandle, > + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock > + ); > + > +/** > + Function returns an array of handles that support the FVB protocol > + in a buffer allocated from pool. > + > + @param[out] NumberHandles The number of handles returned in Buffer= . > + @param[out] Buffer A pointer to the buffer to return the re= quested > + array of handles that support FVB proto= col. > + > + @retval EFI_SUCCESS The array of handles was returned in Buf= fer, and > the number of > + handles in Buffer was returned in Number= Handles. > + @retval EFI_NOT_FOUND No FVB handle was found. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store > the matching results. > + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. > + > +**/ > +EFI_STATUS > +GetFvbCountAndBuffer ( > + OUT UINTN *NumberHandles, > + OUT EFI_HANDLE **Buffer > + ); > + > +/** > + Initializes variable store area for non-volatile and volatile variable= . > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + > +**/ > +EFI_STATUS > +VariableCommonInitialize ( > + VOID > + ); > + > +/** > + This function reclaims variable storage if free size is below the thre= shold. > + > +**/ > +VOID > +ReclaimForOS ( > + VOID > + ); > + > +/** > + Get maximum variable size, covering both non-volatile and volatile var= iables. > + > + @return Maximum variable size. > + > +**/ > +UINTN > +GetMaxVariableSize ( > + VOID > + ); > + > +/** > + Initializes variable write service. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval Others Fail to initialize the variable service. > + > +**/ > +EFI_STATUS > +VariableWriteServiceInitialize ( > + VOID > + ); > + > +/** > + Retrieve the SMM Fault Tolerent Write protocol interface. > + > + @param[out] FtwProtocol The interface of SMM Ftw protocol > + > + @retval EFI_SUCCESS The SMM SAR protocol instance was found = and > returned in SarProtocol. > + @retval EFI_NOT_FOUND The SMM SAR protocol instance was not fo= und. > + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. > + > +**/ > +EFI_STATUS > +GetFtwProtocol ( > + OUT VOID **FtwProtocol > + ); > + > +/** > + Get the proper fvb handle and/or fvb protocol by the given Flash addre= ss. > + > + @param[in] Address The Flash address. > + @param[out] FvbHandle In output, if it is not NULL, it points to t= he proper > FVB handle. > + @param[out] FvbProtocol In output, if it is not NULL, it points to t= he proper > FVB protocol. > + > +**/ > +EFI_STATUS > +GetFvbInfoByAddress ( > + IN EFI_PHYSICAL_ADDRESS Address, > + OUT EFI_HANDLE *FvbHandle OPTIONAL, > + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL > + ); > + > +/** > + > + This code finds variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode, and datasize and data are > external input. > + This function will do basic validation, before parse the data. > + > + @param VariableName Name of Variable to be found. > + @param VendorGuid Variable vendor GUID. > + @param Attributes Attribute value of the variable foun= d. > + @param DataSize Size of Data found. If size is less = than the > + data, this value contains the requir= ed size. > + @param Data The buffer to return the contents of= the variable. > May be NULL > + with a zero DataSize in order to det= ermine the size buffer > needed. > + > + @return EFI_INVALID_PARAMETER Invalid parameter. > + @return EFI_SUCCESS Find the specified variable. > + @return EFI_NOT_FOUND Not found. > + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result= . > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ); > + > +/** > + > + This code Finds the Next available variable. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param VariableNameSize The size of the VariableName buffer.= The > size must be large > + enough to fit input string supplied = in VariableName buffer. > + @param VariableName Pointer to variable name. > + @param VendorGuid Variable Vendor Guid. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND The next variable was not found. > + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small fo= r > the result. > + VariableNameSize has been updated wi= th the size needed > to complete the request. > + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. > + @retval EFI_INVALID_PARAMETER VariableName is NULL. > + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. > + @retval EFI_INVALID_PARAMETER The input values of VariableName and > VendorGuid are not a name and > + GUID of an existing variable. > + @retval EFI_INVALID_PARAMETER Null-terminator is not found in the = first > VariableNameSize bytes of > + the input VariableName buffer. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetNextVariableName ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VendorGuid > + ); > + > +/** > + > + This code sets variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode, and datasize and data are > external input. > + This function will do basic validation, before parse the data. > + This function will parse the authentication carefully to avoid securit= y issues, > like > + buffer overflow, integer overflow. > + This function will check attribute carefully to avoid authentication b= ypass. > + > + @param VariableName Name of Variable to be found. > + @param VendorGuid Variable vendor GUID. > + @param Attributes Attribute value of the variabl= e found > + @param DataSize Size of Data found. If size is= less than the > + data, this value contains the = required size. > + @param Data Data pointer. > + > + @return EFI_INVALID_PARAMETER Invalid parameter. > + @return EFI_SUCCESS Set successfully. > + @return EFI_OUT_OF_RESOURCES Resource not enough to set var= iable. > + @return EFI_NOT_FOUND Not found. > + @return EFI_WRITE_PROTECTED Variable is read-only. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceSetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ); > + > +/** > + > + This code returns information about the EFI variables. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param Attributes Attributes bitmask to specify th= e type of > variables > + on which to return information. > + @param MaximumVariableStorageSize Pointer to the maximum size of t= he > storage space available > + for the EFI variables associated= with the attributes > specified. > + @param RemainingVariableStorageSize Pointer to the remaining size of= the > storage space available > + for EFI variables associated wit= h the attributes specified. > + @param MaximumVariableSize Pointer to the maximum size of a= n > individual EFI variables > + associated with the attributes s= pecified. > + > + @return EFI_SUCCESS Query successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceQueryVariableInfoInternal ( > + IN UINT32 Attributes, > + OUT UINT64 *MaximumVariableStorageSize, > + OUT UINT64 *RemainingVariableStorageSize, > + OUT UINT64 *MaximumVariableSize > + ); > + > +/** > + > + This code returns information about the EFI variables. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param Attributes Attributes bitmask to specify th= e type of > variables > + on which to return information. > + @param MaximumVariableStorageSize Pointer to the maximum size of t= he > storage space available > + for the EFI variables associated= with the attributes > specified. > + @param RemainingVariableStorageSize Pointer to the remaining size of= the > storage space available > + for EFI variables associated wit= h the attributes specified. > + @param MaximumVariableSize Pointer to the maximum size of a= n > individual EFI variables > + associated with the attributes s= pecified. > + > + @return EFI_INVALID_PARAMETER An invalid combination of attrib= ute > bits was supplied. > + @return EFI_SUCCESS Query successfully. > + @return EFI_UNSUPPORTED The attribute is not supported o= n this > platform. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceQueryVariableInfo ( > + IN UINT32 Attributes, > + OUT UINT64 *MaximumVariableStorageSize, > + OUT UINT64 *RemainingVariableStorageSize, > + OUT UINT64 *MaximumVariableSize > + ); > + > +/** > + Mark a variable that will become read-only after leaving the DXE phase= of > execution. > + > + @param[in] This The VARIABLE_LOCK_PROTOCOL instance. > + @param[in] VariableName A pointer to the variable name that will be m= ade > read-only subsequently. > + @param[in] VendorGuid A pointer to the vendor GUID that will be mad= e > read-only subsequently. > + > + @retval EFI_SUCCESS The variable specified by the VariableNa= me and > the VendorGuid was marked > + as pending to be read-only. > + @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL. > + Or VariableName is an empty string. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the > lock request. > +**/ > +EFI_STATUS > +EFIAPI > +VariableLockRequestToLock ( > + IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ); > + > +/** > + Register SetVariable check handler. > + > + @param[in] Handler Pointer to check handler. > + > + @retval EFI_SUCCESS The SetVariable check handler was regist= ered > successfully. > + @retval EFI_INVALID_PARAMETER Handler is NULL. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > SetVariable check handler register request. > + @retval EFI_UNSUPPORTED This interface is not implemented. > + For example, it is unsupported in VarChe= ck protocol if both > VarCheck and SmmVarCheck protocols are present. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckRegisterSetVariableCheckHandler ( > + IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler > + ); > + > +/** > + Variable property set. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[in] VariableProperty Pointer to the input variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was set successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string, > + or the fields of VariableProperty are no= t valid. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > variable property set request. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertySet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ); > + > +/** > + Variable property get. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[out] VariableProperty Pointer to the output variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was got successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string. > + @retval EFI_NOT_FOUND The property of variable specified by th= e Name > and Guid was not found. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertyGet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ); > + > +/** > + Initialize variable quota. > + > +**/ > +VOID > +InitializeVariableQuota ( > + VOID > + ); > + > +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; > +extern EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache; > +extern VARIABLE_STORE_HEADER *mNvVariableCache; > +extern VARIABLE_INFO_ENTRY *gVariableInfo; > +extern BOOLEAN mEndOfDxe; > +extern VAR_CHECK_REQUEST_SOURCE mRequestSource; > + > +extern AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut; > + > +/** > + Finds variable in storage blocks of volatile and non-volatile storage = areas. > + > + This code finds variable in storage blocks of volatile and non-volatil= e storage > areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Variable vendor GUID to be found. > + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO struct= ure > for > + output of the variable found. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty stri= ng, > + while VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibFindVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT AUTH_VARIABLE_INFO *AuthVariableInfo > + ); > + > +/** > + Finds next variable in storage blocks of volatile and non-volatile sto= rage areas. > + > + This code finds next variable in storage blocks of volatile and non-vo= latile > storage areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Variable vendor GUID to be found. > + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO struct= ure > for > + output of the next variable. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty stri= ng, > + while VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibFindNextVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT AUTH_VARIABLE_INFO *AuthVariableInfo > + ); > + > +/** > + Update the variable region with Variable information. > + > + @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure= for > + input of the variable. > + > + @retval EFI_SUCCESS The update operation is success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_WRITE_PROTECTED Variable is write-protected. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibUpdateVariable ( > + IN AUTH_VARIABLE_INFO *AuthVariableInfo > + ); > + > +/** > + Get scratch buffer. > + > + @param[in, out] ScratchBufferSize Scratch buffer size. If input size i= s greater > than > + the maximum supported buffer size, t= his value contains > + the maximum supported buffer size as= output. > + @param[out] ScratchBuffer Pointer to scratch buffer address. > + > + @retval EFI_SUCCESS Get scratch buffer successfully. > + @retval EFI_UNSUPPORTED If input size is greater than the maximum > supported buffer size. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibGetScratchBuffer ( > + IN OUT UINTN *ScratchBufferSize, > + OUT VOID **ScratchBuffer > + ); > + > +/** > + This function is to check if the remaining variable space is enough to= set > + all Variables from argument list successfully. The purpose of the chec= k > + is to keep the consistency of the Variables to be in variable storage. > + > + Note: Variables are assumed to be in same storage. > + The set sequence of Variables will be same with the sequence of Variab= leEntry > from argument list, > + so follow the argument sequence to check the Variables. > + > + @param[in] Attributes Variable attributes for Variable entries= . > + @param ... The variable argument list with type > VARIABLE_ENTRY_CONSISTENCY *. > + A NULL terminates the list. The Variable= Size of > + VARIABLE_ENTRY_CONSISTENCY is the variab= le data size as > input. > + It will be changed to variable total siz= e as output. > + > + @retval TRUE Have enough variable space to set the Va= riables > successfully. > + @retval FALSE No enough variable space to set the Vari= ables > successfully. > + > +**/ > +BOOLEAN > +EFIAPI > +VariableExLibCheckRemainingSpaceForConsistency ( > + IN UINT32 Attributes, > + ... > + ); > + > +/** > + Return TRUE if at OS runtime. > + > + @retval TRUE If at OS runtime. > + @retval FALSE If at boot time. > + > +**/ > +BOOLEAN > +EFIAPI > +VariableExLibAtRuntime ( > + VOID > + ); > + > +/** > + Is user variable? > + > + @param[in] Variable Pointer to variable header. > + > + @retval TRUE User variable. > + @retval FALSE System variable. > + > +**/ > +BOOLEAN > +IsUserVariable ( > + IN VARIABLE_HEADER *Variable > + ); > + > +/** > + > + Variable store garbage collection and reclaim operation. > + > + @param[in] VariableBase Base address of variable store= . > + @param[out] LastVariableOffset Offset of last variable. > + @param[in] IsVolatile The variable store is volatile= or not; > + if it is non-volatile, need FT= W. > + @param[in, out] UpdatingPtrTrack Pointer to updating variable p= ointer > track structure. > + @param[in] NewVariable Pointer to new variable. > + @param[in] NewVariableSize New variable size. > + > + @return EFI_SUCCESS Reclaim operation has finished su= ccessfully. > + @return EFI_OUT_OF_RESOURCES No enough memory resources or > variable space. > + @return Others Unexpect error happened during re= claim > operation. > + > +**/ > +EFI_STATUS > +Reclaim ( > + IN EFI_PHYSICAL_ADDRESS VariableBase, > + OUT UINTN *LastVariableOffset, > + IN BOOLEAN IsVolatile, > + IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack, > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN NewVariableSize > + ); > + > +/** > + > + This function writes data to the FWH at the correct LBA even if the LB= As > + are fragmented. > + > + @param Global Pointer to VARIABLE_GLOBAL structure. > + @param Volatile Point out the Variable is Volatile or N= on-Volatile. > + @param SetByIndex TRUE if target pointer is given as inde= x. > + FALSE if target pointer is absolute. > + @param Fvb Pointer to the writable FVB protocol. > + @param DataPtrIndex Pointer to the Data from the end of > VARIABLE_STORE_HEADER > + structure. > + @param DataSize Size of data to be written. > + @param Buffer Pointer to the buffer from which data i= s written. > + > + @retval EFI_INVALID_PARAMETER Parameters not valid. > + @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable > update. > + @retval EFI_OUT_OF_RESOURCES The remaining size is not enough. > + @retval EFI_SUCCESS Variable store successfully updated. > + > +**/ > +EFI_STATUS > +UpdateVariableStore ( > + IN VARIABLE_GLOBAL *Global, > + IN BOOLEAN Volatile, > + IN BOOLEAN SetByIndex, > + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, > + IN UINTN DataPtrIndex, > + IN UINT32 DataSize, > + IN UINT8 *Buffer > + ); > + > +/** > + Update partial data of a variable on NV storage and/or cached copy. > + > + @param[in] VariableInfo Pointer to a variable with detailed informat= ion. > + @param[in] Offset Offset to write from. > + @param[in] Size Size of data Buffer to update. > + @param[in] Buffer Pointer to data buffer to update. > + > + @retval EFI_SUCCESS The variable data was updated successf= ully. > + @retval EFI_UNSUPPORTED If this function is called directly in= runtime. > + @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are no= t > valid. > + @retval Others Failed to update NV storage or variabl= e cache. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibUpdateNvVariable ( > + IN PROTECTED_VARIABLE_INFO *VariableInfo, > + IN UINTN Offset, > + IN UINT32 Size, > + IN UINT8 *Buffer > + ); > + > +/** > + Finds the given variable in a variable store in SMM. > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully to > avoid buffer overflow. [JianJW] Too long line. Wrap it to within 80 characters for each line. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be= found. > + > +**/ > +EFI_STATUS > +EFIAPI > +FindVariableInSmm ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ); > + > +#endif > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.h > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.h > new file mode 100644 > index 000000000000..a84db4877c13 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.h > @@ -0,0 +1,67 @@ > +/** @file > + Common variable non-volatile store routines. > + > +Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef VARIABLE_NON_VOLATILE_H_ > +#define VARIABLE_NON_VOLATILE_H_ > + > +#include "Variable.h" > + > +/** > + Get non-volatile maximum variable size. > + > + @return Non-volatile maximum variable size. > + > +**/ > +UINTN > +GetNonVolatileMaxVariableSize ( > + VOID > + ); > + > +/** > + Init emulated non-volatile variable store. > + > + @param[out] VariableStoreBase Output pointer to emulated non-volatile > variable store base. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + > +**/ > +EFI_STATUS > +InitEmuNonVolatileVariableStore ( > + EFI_PHYSICAL_ADDRESS *VariableStoreBase > + ); > + > +/** > + Init real non-volatile variable store. > + > + @param[out] VariableStoreBase Output pointer to real non-volatile vari= able > store base. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for > Variable Store is corrupted. > + > +**/ > +EFI_STATUS > +InitRealNonVolatileVariableStore ( > + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase > + ); > + > +/** > + Init non-volatile variable store. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for > Variable Store is corrupted. > + > +**/ > +EFI_STATUS > +InitNonVolatileVariableStore ( > + VOID > + ); > + > +#endif > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h > new file mode 100644 > index 000000000000..5b040e00982f > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.h > @@ -0,0 +1,424 @@ > +/** @file > + Functions in this module are associated with variable parsing operatio= ns and > + are intended to be usable across variable driver source files. > + > +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef VARIABLE_PARSING_H_ > +#define VARIABLE_PARSING_H_ > + > +#include > +#include "Variable.h" > + > +/** > + > + This code checks if variable header is valid or not. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] VariableStoreEnd Pointer to the Variable Store End. > + @param[in] AuthFormat Auth-variable indicator. > + > + @retval TRUE Variable header is valid. > + @retval FALSE Variable header is not valid. > + > +**/ > +BOOLEAN > +IsValidVariableHeader ( > + IN VARIABLE_HEADER *Variable, > + IN VARIABLE_HEADER *VariableStoreEnd, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + This code gets the current status of Variable Store. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @retval EfiRaw Variable store status is raw. > + @retval EfiValid Variable store status is valid. > + @retval EfiInvalid Variable store status is invalid. > + > +**/ > +VARIABLE_STORE_STATUS > +GetVariableStoreStatus ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ); > + > +/** > + This code gets the size of variable header. > + > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return Size of variable header in bytes in type UINTN. > + > +**/ > +UINTN > +GetVariableHeaderSize ( > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + This code gets the size of name of variable. > + > + @param[in] Variable Pointer to the variable header. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return UINTN Size of variable in bytes. > + > +**/ > +UINTN > +NameSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + This code sets the size of name of variable. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] NameSize Name size to set. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > +**/ > +VOID > +SetNameSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN UINTN NameSize, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + This code gets the size of variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return Size of variable in bytes. > + > +**/ > +UINTN > +DataSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + This code sets the size of variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] DataSize Data size to set. > + @param[in] AuthFormat TRUE indicates authenticated variables are used. > + FALSE indicates authenticated variables are not = used. > + > +**/ > +VOID > +SetDataSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN UINTN DataSize, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + This code gets the pointer to the variable name. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to Variable Name which is Unicode encoding. > + > +**/ > +CHAR16 * > +GetVariableNamePtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + This code gets the pointer to the variable guid. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return A EFI_GUID* pointer to Vendor Guid. > + > +**/ > +EFI_GUID * > +GetVendorGuidPtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + This code gets the pointer to the variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to Variable Data. > + > +**/ > +UINT8 * > +GetVariableDataPtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + This code gets the variable data offset related to variable header. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Variable Data offset. > + > +**/ > +UINTN > +GetVariableDataOffset ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + Get variable data payload. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[out] Data Pointer to buffer used to store the varia= ble data. > + @param[in] DataSize Size of buffer passed by Data. > + @param[out] DataSize Size of data copied into Data buffer. > + @param[in] AuthFlag Auth-variable indicator. > + > + @return EFI_SUCCESS Data was fetched. > + @return EFI_INVALID_PARAMETER DataSize is NULL. > + @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of varia= ble > data. > + > +**/ > +EFI_STATUS > +GetVariableData ( > + IN VARIABLE_HEADER *Variable, > + IN OUT VOID *Data, > + IN OUT UINT32 *DataSize, > + IN BOOLEAN AuthFlag > + ); > + > +/** > + > + This code gets the pointer to the next variable header. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to next variable header. > + > +**/ > +VARIABLE_HEADER * > +GetNextVariablePtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + > + Gets the pointer to the first variable header in given variable store = area. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @return Pointer to the first variable header. > + > +**/ > +VARIABLE_HEADER * > +GetStartPointer ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ); > + > +/** > + > + Gets the pointer to the end of the variable storage area. > + > + This function gets pointer to the end of the variable storage > + area, according to the input variable store header. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @return Pointer to the end of the variable storage area. > + > +**/ > +VARIABLE_HEADER * > +GetEndPointer ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ); > + > +/** > + Compare two EFI_TIME data. > + > + > + @param[in] FirstTime A pointer to the first EFI_TIME data. > + @param[in] SecondTime A pointer to the second EFI_TIME data. > + > + @retval TRUE The FirstTime is not later than the SecondT= ime. > + @retval FALSE The FirstTime is later than the SecondTime. > + > +**/ > +BOOLEAN > +VariableCompareTimeStampInternal ( > + IN EFI_TIME *FirstTime, > + IN EFI_TIME *SecondTime > + ); > + > +/** > + Find the variable in the specified variable store. > + > + @param[in] VariableName Name of the variable to be found > + @param[in] VendorGuid Vendor GUID to be found. > + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCES= S > attribute > + check at runtime when searching v= ariable. > + @param[in, out] PtrTrack Variable Track Pointer structure = that contains > Variable Information. > + @param[in] AuthFormat TRUE indicates authenticated vari= ables are > used. > + FALSE indicates authenticated var= iables are not used. > + > + @retval EFI_SUCCESS Variable found successfully > + @retval EFI_NOT_FOUND Variable not found > +**/ > +EFI_STATUS > +FindVariableEx ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN BOOLEAN IgnoreRtCheck, > + IN OUT VARIABLE_POINTER_TRACK *PtrTrack, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + This code finds the next available variable. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param[in] VariableName Pointer to variable name. > + @param[in] VendorGuid Variable Vendor Guid. > + @param[in] VariableStoreList A list of variable stores that should be= used to > get the next variable. > + The maximum number of entries is the max= value of > VARIABLE_STORE_TYPE. > + @param[out] VariablePtr Pointer to variable header address. > + @param[in] AuthFormat TRUE indicates authenticated variables a= re used. > + FALSE indicates authenticated variables = are not used. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND The next variable was not found. > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, > while VendorGuid is NULL. > + @retval EFI_INVALID_PARAMETER The input values of VariableName and > VendorGuid are not a name and > + GUID of an existing variable. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetNextVariableInternal ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VARIABLE_STORE_HEADER **VariableStoreList, > + OUT VARIABLE_HEADER **VariablePtr, > + IN BOOLEAN AuthFormat > + ); > + > +/** > + Routine used to track statistical information about variable usage. > + The data is stored in the EFI system table so it can be accessed later= . > + VariableInfo.efi can dump out the table. Only Boot Services variable > + accesses are tracked by this code. The PcdVariableCollectStatistics > + build flag controls if this feature is enabled. > + > + A read that hits in the cache will have Read and Cache true for > + the transaction. Data is allocated by this routine, but never > + freed. > + > + @param[in] VariableName Name of the Variable to track. > + @param[in] VendorGuid Guid of the Variable to track. > + @param[in] Volatile TRUE if volatile FALSE if non-volatile. > + @param[in] Read TRUE if GetVariable() was called. > + @param[in] Write TRUE if SetVariable() was called. > + @param[in] Delete TRUE if deleted via SetVariable(). > + @param[in] Cache TRUE for a cache hit. > + @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_E= NTRY > structures. > + > +**/ > +VOID > +UpdateVariableInfo ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN BOOLEAN Volatile, > + IN BOOLEAN Read, > + IN BOOLEAN Write, > + IN BOOLEAN Delete, > + IN BOOLEAN Cache, > + IN OUT VARIABLE_INFO_ENTRY **VariableInfo > + ); > + > +/** > + > + Retrieve details of the variable next to given variable within Variabl= eStore. > + > + If VariableInfo->StoreIndex is invalid, the first one in VariableStore= is returned. > + > + @param[in,out] VariableInfo Pointer to variable informatio= n. > + > + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL. > + @retval EFI_NOT_FOUND If the end of VariableStore is reached. > + @retval EFI_SUCCESS The next variable is retrieved successf= ully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetNextVariableInfo ( > + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo > + ); > + > +/** > + > + Retrieve details about a variable and return them in VariableInfo->Hea= der. > + > + If VariableInfo->Buffer is given, this function will calculate its off= set > + relative to given variable storage via VariableStore; Otherwise, it wi= ll try > + other internal variable storages or cached copies. It's assumed that, = for all > + copies of NV variable storage, all variables are stored in the same re= lative > + position. If VariableInfo->Buffer is found in the range of any storage= copies, > + its offset relative to that storage should be the same in other copies= . > + > + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Buff= er, > + this function will return the variable memory address inside VariableS= tore, > + if given, via VariableInfo->Address; Otherwise, the address of other s= torage > + copies will be returned, if any. > + > + For a new variable whose offset has not been determined, a value of -1= as > + VariableInfo->Offset should be passed to skip the offset calculation. > + > + @param VariableInfo Pointer to variable information. > + > + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableIn= fo- > >Address > + and VariableInfo->Offset are NULL (0). > + @retval EFI_NOT_FOUND If given Address or Offset is out of ra= nge of > + any given or internal storage copies. > + @retval EFI_SUCCESS Variable details are retrieved successf= ully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetVariableInfo ( > + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo > + ); > + > +#endif > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.h > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.h > new file mode 100644 > index 000000000000..77dbce0f907c > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.h > @@ -0,0 +1,51 @@ > +/** @file > + The common variable volatile store routines shared by the DXE_RUNTIME > variable > + module and the DXE_SMM variable module. > + > +Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef VARIABLE_RUNTIME_CACHE_H_ > +#define VARIABLE_RUNTIME_CACHE_H_ > + > +#include "Variable.h" > + > +/** > + Copies any pending updates to runtime variable caches. > + > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated success= fully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ); > + > +/** > + Synchronizes the runtime variable caches with all pending updates outs= ide > runtime. > + > + Ensures all conditions are met to maintain coherency for runtime cache > updates. This function will attempt > + to write the given update (and any other pending updates) if the ReadL= ock is > available. Otherwise, the > + update is added as a pending update for the given variable store and i= t will be > flushed to the runtime cache > + at the next opportunity the ReadLock is available. > + > + @param[in] VariableRuntimeCache Variable runtime cache structure for t= he > runtime cache being synchronized. > + @param[in] Offset Offset in bytes to apply the update. > + @param[in] Length Length of data in bytes of the update. > + > + @retval EFI_SUCCESS The update was added as a pending upda= te > successfully. If the variable runtime > + cache ReadLock was available, the runt= ime cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + > +**/ > +EFI_STATUS > +SynchronizeRuntimeVariableCache ( > + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, > + IN UINTN Offset, > + IN UINTN Length > + ); > + > +#endif > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c > new file mode 100644 > index 000000000000..c15cce97165d > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Measurement.c > @@ -0,0 +1,343 @@ > +/** @file > + Measure TCG required variable. > + > +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "PrivilegePolymorphic.h" > + > +typedef struct { > + CHAR16 *VariableName; > + EFI_GUID *VendorGuid; > +} VARIABLE_TYPE; > + > +VARIABLE_TYPE mVariableType[] =3D { > + { EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid }, > + { EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid }, > + { EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid }, > + { EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid }, > + { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, > + { EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid }, > +}; > + > +// > +// "SecureBoot" may update following PK Del/Add > +// Cache its value to detect value update > +// > +UINT8 *mSecureBootVarData =3D NULL; > +UINTN mSecureBootVarDataSize =3D 0; > + > +/** > + This function will return if this variable is SecureBootPolicy Variabl= e. > + > + @param[in] VariableName A Null-terminated string that is the nam= e of the > vendor's variable. > + @param[in] VendorGuid A unique identifier for the vendor. > + > + @retval TRUE This is SecureBootPolicy Variable > + @retval FALSE This is not SecureBootPolicy Variable > +**/ > +BOOLEAN > +IsSecureBootPolicyVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + UINTN Index; > + > + for (Index =3D 0; Index < sizeof (mVariableType)/sizeof (mVariableType= [0]); > Index++) { > + if ((StrCmp (VariableName, mVariableType[Index].VariableName) =3D=3D= 0) && > + (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) > + { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + Measure and log an EFI variable, and extend the measurement result int= o a > specific PCR. > + > + @param[in] VarName A Null-terminated string that is the nam= e of the > vendor's variable. > + @param[in] VendorGuid A unique identifier for the vendor. > + @param[in] VarData The content of the variable data. > + @param[in] VarSize The size of the variable data. > + > + @retval EFI_SUCCESS Operation completed successfully. > + @retval EFI_OUT_OF_RESOURCES Out of memory. > + @retval EFI_DEVICE_ERROR The operation was unsuccessful. > + > +**/ > +EFI_STATUS > +EFIAPI > +MeasureVariable ( > + IN CHAR16 *VarName, > + IN EFI_GUID *VendorGuid, > + IN VOID *VarData, > + IN UINTN VarSize > + ) > +{ > + EFI_STATUS Status; > + UINTN VarNameLength; > + UEFI_VARIABLE_DATA *VarLog; > + UINT32 VarLogSize; > + > + ASSERT ((VarSize =3D=3D 0 && VarData =3D=3D NULL) || (VarSize !=3D 0 &= & VarData !=3D > NULL)); > + > + VarNameLength =3D StrLen (VarName); > + VarLogSize =3D (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof > (*VarName) + VarSize > + - sizeof (VarLog->UnicodeName) - sizeof (VarL= og- > >VariableData)); > + > + VarLog =3D (UEFI_VARIABLE_DATA *)AllocateZeroPool (VarLogSize); > + if (VarLog =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + CopyMem (&VarLog->VariableName, VendorGuid, sizeof (VarLog- > >VariableName)); > + VarLog->UnicodeNameLength =3D VarNameLength; > + VarLog->VariableDataLength =3D VarSize; > + CopyMem ( > + VarLog->UnicodeName, > + VarName, > + VarNameLength * sizeof (*VarName) > + ); > + if (VarSize !=3D 0) { > + CopyMem ( > + (CHAR16 *)VarLog->UnicodeName + VarNameLength, > + VarData, > + VarSize > + ); > + } > + > + DEBUG ((DEBUG_INFO, "VariableDxe: MeasureVariable (Pcr - %x, EventType= - > %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_DRIVER_CONFIG)); > + DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, > VendorGuid)); > + > + Status =3D TpmMeasureAndLogData ( > + 7, > + EV_EFI_VARIABLE_DRIVER_CONFIG, > + VarLog, > + VarLogSize, > + VarLog, > + VarLogSize > + ); > + FreePool (VarLog); > + return Status; > +} > + > +/** > + Returns the status whether get the variable success. The function retr= ieves > + variable through the UEFI Runtime Service GetVariable(). The > + returned buffer is allocated using AllocatePool(). The caller is resp= onsible > + for freeing this buffer with FreePool(). > + > + This API is only invoked in boot time. It may NOT be invoked at runtim= e. > + > + @param[in] Name The pointer to a Null-terminated Unicode string. > + @param[in] Guid The pointer to an EFI_GUID structure > + @param[out] Value The buffer point saved the variable info. > + @param[out] Size The buffer size of the variable. > + > + @return EFI_OUT_OF_RESOURCES Allocate buffer failed. > + @return EFI_SUCCESS Find the specified variable. > + @return Others Errors Return errors from call to gRT->GetV= ariable. > + > +**/ > +EFI_STATUS > +InternalGetVariable ( > + IN CONST CHAR16 *Name, > + IN CONST EFI_GUID *Guid, > + OUT VOID **Value, > + OUT UINTN *Size > + ) > +{ > + EFI_STATUS Status; > + UINTN BufferSize; > + > + // > + // Try to get the variable size. > + // > + BufferSize =3D 0; > + *Value =3D NULL; > + if (Size !=3D NULL) { > + *Size =3D 0; > + } > + > + Status =3D gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, > &BufferSize, *Value); > + if (Status !=3D EFI_BUFFER_TOO_SMALL) { > + return Status; > + } > + > + // > + // Allocate buffer to get the variable. > + // > + *Value =3D AllocatePool (BufferSize); > + ASSERT (*Value !=3D NULL); > + if (*Value =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Get the variable data. > + // > + Status =3D gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, > &BufferSize, *Value); > + if (EFI_ERROR (Status)) { > + FreePool (*Value); > + *Value =3D NULL; > + } > + > + if (Size !=3D NULL) { > + *Size =3D BufferSize; > + } > + > + return Status; > +} > + > +/** > + SecureBoot Hook for SetVariable. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + > +**/ > +VOID > +EFIAPI > +SecureBootHook ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN VariableDataSize; > + VOID *VariableData; > + > + if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) { > + return; > + } > + > + // > + // We should NOT use Data and DataSize here,because it may include > signature, > + // or is just partial with append attributes, or is deleted. > + // We should GetVariable again, to get full variable content. > + // > + Status =3D InternalGetVariable ( > + VariableName, > + VendorGuid, > + &VariableData, > + &VariableDataSize > + ); > + if (EFI_ERROR (Status)) { > + // > + // Measure DBT only if present and not empty > + // > + if ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) =3D=3D 0) &= & > + CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) > + { > + DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted= \n", > EFI_IMAGE_SECURITY_DATABASE2)); > + return; > + } else { > + VariableData =3D NULL; > + VariableDataSize =3D 0; > + } > + } > + > + Status =3D MeasureVariable ( > + VariableName, > + VendorGuid, > + VariableData, > + VariableDataSize > + ); > + DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status)); > + > + if (VariableData !=3D NULL) { > + FreePool (VariableData); > + } > + > + // > + // "SecureBoot" is 8bit & read-only. It can only be changed according = to PK > update > + // > + if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) =3D=3D 0) && > + CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) > + { > + Status =3D InternalGetVariable ( > + EFI_SECURE_BOOT_MODE_NAME, > + &gEfiGlobalVariableGuid, > + &VariableData, > + &VariableDataSize > + ); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + // > + // If PK update is successful. "SecureBoot" shall always exist ever = since > variable write service is ready > + // > + ASSERT (mSecureBootVarData !=3D NULL); > + > + if (CompareMem (mSecureBootVarData, VariableData, VariableDataSize) = !=3D > 0) { > + FreePool (mSecureBootVarData); > + mSecureBootVarData =3D VariableData; > + mSecureBootVarDataSize =3D VariableDataSize; > + > + DEBUG ((DEBUG_INFO, "%s variable updated according to PK change. > Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME)); > + Status =3D MeasureVariable ( > + EFI_SECURE_BOOT_MODE_NAME, > + &gEfiGlobalVariableGuid, > + mSecureBootVarData, > + mSecureBootVarDataSize > + ); > + DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status)); > + } else { > + // > + // "SecureBoot" variable is not changed > + // > + FreePool (VariableData); > + } > + } > + > + return; > +} > + > +/** > + Some Secure Boot Policy Variable may update following other variable > changes(SecureBoot follows PK change, etc). > + Record their initial State when variable write service is ready. > + > +**/ > +VOID > +EFIAPI > +RecordSecureBootPolicyVarData ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Record initial "SecureBoot" variable value. > + // It is used to detect SecureBoot variable change in SecureBootHook. > + // > + Status =3D InternalGetVariable ( > + EFI_SECURE_BOOT_MODE_NAME, > + &gEfiGlobalVariableGuid, > + (VOID **)&mSecureBootVarData, > + &mSecureBootVarDataSize > + ); > + if (EFI_ERROR (Status)) { > + // > + // Read could fail when Auth Variable solution is not supported > + // > + DEBUG ((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s > Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status)); > + } > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c > new file mode 100644 > index 000000000000..a5b7f8a1fbe2 > --- /dev/null > +++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Reclaim.c > @@ -0,0 +1,504 @@ > +/** @file > + Handles non-volatile variable store garbage collection, using FTW > + (Fault Tolerant Write) protocol. > + > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > +#include "VariableNonVolatile.h" > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +/** > + Gets LBA of block and offset by given address. > + > + This function gets the Logical Block Address (LBA) of a firmware > + volume block containing the given address, and the offset of the > + address on the block. > + > + @param Address Address which should be contained > + by returned FVB handle. > + @param Lba Pointer to LBA for output. > + @param Offset Pointer to offset for output. > + > + @retval EFI_SUCCESS LBA and offset successfully returned. > + @retval EFI_NOT_FOUND Fail to find FVB handle by address. > + @retval EFI_ABORTED Fail to find valid LBA and offset. > + > +**/ > +EFI_STATUS > +GetLbaAndOffsetByAddress ( > + IN EFI_PHYSICAL_ADDRESS Address, > + OUT EFI_LBA *Lba, > + OUT UINTN *Offset > + ) > +{ > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS FvbBaseAddress; > + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; > + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; > + EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; > + UINT32 LbaIndex; > + > + Fvb =3D NULL; > + *Lba =3D (EFI_LBA)(-1); > + *Offset =3D 0; > + > + // > + // Get the proper FVB protocol. > + // > + Status =3D GetFvbInfoByAddress (Address, NULL, &Fvb); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Get the Base Address of FV. > + // > + Status =3D Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER > *)((UINTN)FvbBaseAddress); > + > + // > + // Get the (LBA, Offset) of Address. > + // > + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { > + // > + // BUGBUG: Assume one FV has one type of BlockLength. > + // > + FvbMapEntry =3D &FwVolHeader->BlockMap[0]; > + for (LbaIndex =3D 1; LbaIndex <=3D FvbMapEntry->NumBlocks; LbaIndex = +=3D 1) { > + if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { > + // > + // Found the (Lba, Offset). > + // > + *Lba =3D LbaIndex - 1; > + *Offset =3D (UINTN)(Address - (FvbBaseAddress + FvbMapEntry->Len= gth * > (LbaIndex - 1))); > + return EFI_SUCCESS; > + } > + } > + } > + > + return EFI_ABORTED; > +} > + > +/** > + Writes a buffer to variable storage space, in the working block. > + > + This function writes a buffer to variable storage space into a firmwar= e > + volume block device. The destination is specified by parameter > + VariableBase. Fault Tolerant Write protocol is used for writing. > + > + @param VariableBase Base address of variable to write > + @param VariableBuffer Point to the variable data buffer. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. > + @retval EFI_ABORTED The function could not complete successfully. > + > +**/ > +EFI_STATUS > +FtwVariableSpace ( > + IN EFI_PHYSICAL_ADDRESS VariableBase, > + IN VARIABLE_STORE_HEADER *VariableBuffer > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE FvbHandle; > + EFI_LBA VarLba; > + UINTN VarOffset; > + UINTN FtwBufferSize; > + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; > + > + // > + // Locate fault tolerant write protocol. > + // > + Status =3D GetFtwProtocol ((VOID **)&FtwProtocol); > + if (EFI_ERROR (Status)) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Locate Fvb handle by address. > + // > + Status =3D GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Get LBA and Offset by address. > + // > + Status =3D GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset= ); > + if (EFI_ERROR (Status)) { > + return EFI_ABORTED; > + } > + > + FtwBufferSize =3D ((VARIABLE_STORE_HEADER *)((UINTN)VariableBase))->Si= ze; > + ASSERT (FtwBufferSize =3D=3D VariableBuffer->Size); > + > + // > + // FTW write record. > + // > + Status =3D FtwProtocol->Write ( > + FtwProtocol, > + VarLba, // LBA > + VarOffset, // Offset > + FtwBufferSize, // NumBytes > + NULL, // PrivateData NULL > + FvbHandle, // Fvb Handle > + (VOID *)VariableBuffer // write buffer > + ); > + > + return Status; > +} > + > +/** > + > + Variable store garbage collection and reclaim operation. > + > + @param[in] VariableBase Base address of variable store= . > + @param[out] LastVariableOffset Offset of last variable. > + @param[in] IsVolatile The variable store is volatile= or not; > + if it is non-volatile, need FT= W. > + @param[in, out] UpdatingPtrTrack Pointer to updating variable p= ointer > track structure. > + @param[in] NewVariable Pointer to new variable. > + @param[in] NewVariableSize New variable size. > + > + @return EFI_SUCCESS Reclaim operation has finished su= ccessfully. > + @return EFI_OUT_OF_RESOURCES No enough memory resources or > variable space. > + @return Others Unexpect error happened during re= claim > operation. > + > +**/ > +EFI_STATUS > +Reclaim ( > + IN EFI_PHYSICAL_ADDRESS VariableBase, > + OUT UINTN *LastVariableOffset, > + IN BOOLEAN IsVolatile, > + IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack, > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN NewVariableSize > + ) > +{ > + VARIABLE_HEADER *Variable; > + VARIABLE_HEADER *AddedVariable; > + VARIABLE_HEADER *NextVariable; > + VARIABLE_HEADER *NextAddedVariable; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + UINT8 *ValidBuffer; > + UINTN MaximumBufferSize; > + UINTN VariableSize; > + UINTN NameSize; > + UINT8 *CurrPtr; > + VOID *Point0; > + VOID *Point1; > + BOOLEAN FoundAdded; > + EFI_STATUS Status; > + EFI_STATUS DoneStatus; > + UINTN CommonVariableTotalSize; > + UINTN CommonUserVariableTotalSize; > + UINTN HwErrVariableTotalSize; > + VARIABLE_HEADER *UpdatingVariable; > + VARIABLE_HEADER *UpdatingInDeletedTransition; > + BOOLEAN AuthFormat; > + > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.= AuthFormat; > + UpdatingVariable =3D NULL; > + UpdatingInDeletedTransition =3D NULL; > + if (UpdatingPtrTrack !=3D NULL) { > + UpdatingVariable =3D UpdatingPtrTrack->CurrPtr; > + UpdatingInDeletedTransition =3D UpdatingPtrTrack->InDeletedTransitio= nPtr; > + } > + > + VariableStoreHeader =3D (VARIABLE_STORE_HEADER *)((UINTN)VariableBase)= ; > + > + CommonVariableTotalSize =3D 0; > + CommonUserVariableTotalSize =3D 0; > + HwErrVariableTotalSize =3D 0; > + > + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + // > + // Start Pointers for the variable. > + // > + Variable =3D GetStartPointer (VariableStoreHeader); > + MaximumBufferSize =3D sizeof (VARIABLE_STORE_HEADER); > + > + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStore= Header), > AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); > + if (((Variable->State =3D=3D VAR_ADDED) || (Variable->State =3D=3D > (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) && > + (Variable !=3D UpdatingVariable) && > + (Variable !=3D UpdatingInDeletedTransition) > + ) > + { > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + MaximumBufferSize +=3D VariableSize; > + } > + > + Variable =3D NextVariable; > + } > + > + if (NewVariable !=3D NULL) { > + // > + // Add the new variable size. > + // > + MaximumBufferSize +=3D NewVariableSize; > + } > + > + // > + // Reserve the 1 Bytes with Oxff to identify the > + // end of the variable buffer. > + // > + MaximumBufferSize +=3D 1; > + ValidBuffer =3D AllocatePool (MaximumBufferSize); > + if (ValidBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + // > + // For NV variable reclaim, don't allocate pool here and just use > mNvVariableCache > + // as the buffer to reduce SMRAM consumption for SMM variable driver= . > + // > + MaximumBufferSize =3D mNvVariableCache->Size; > + ValidBuffer =3D (UINT8 *)mNvVariableCache; > + } > + > + SetMem (ValidBuffer, MaximumBufferSize, 0xff); > + > + // > + // Copy variable store header. > + // > + CopyMem (ValidBuffer, VariableStoreHeader, sizeof > (VARIABLE_STORE_HEADER)); > + CurrPtr =3D (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBu= ffer); > + > + // > + // Reinstall all ADDED variables as long as they are not identical to = Updating > Variable. > + // > + Variable =3D GetStartPointer (VariableStoreHeader); > + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHe= ader), > AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); > + if ((Variable !=3D UpdatingVariable) && (Variable->State =3D=3D VAR_= ADDED)) { > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize); > + if (!IsVolatile) { > + (VOID)ProtectedVariableLibRefresh ( > + (VARIABLE_HEADER *)CurrPtr, > + VariableSize, > + (UINTN)CurrPtr - (UINTN)ValidBuffer, > + FALSE > + ); > + > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) > + =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) > + { > + HwErrVariableTotalSize +=3D VariableSize; > + } else { > + CommonVariableTotalSize +=3D VariableSize; > + if (IsUserVariable (Variable)) { > + CommonUserVariableTotalSize +=3D VariableSize; > + } > + } > + } > + > + CurrPtr +=3D VariableSize; > + } > + > + Variable =3D NextVariable; > + } > + > + // > + // Reinstall all in delete transition variables. > + // > + Variable =3D GetStartPointer (VariableStoreHeader); > + while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHe= ader), > AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); > + if ((Variable !=3D UpdatingVariable) && (Variable !=3D > UpdatingInDeletedTransition) && (Variable->State =3D=3D > (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) && > + (ProtectedVariableLibIsHmac (GetVariableNamePtr (Variable, AuthF= ormat)) > =3D=3D FALSE)) > + { > + FoundAdded =3D FALSE; > + AddedVariable =3D GetStartPointer ((VARIABLE_STORE_HEADER *)ValidB= uffer); > + while (IsValidVariableHeader (AddedVariable, GetEndPointer > ((VARIABLE_STORE_HEADER *)ValidBuffer), AuthFormat)) { > + NextAddedVariable =3D GetNextVariablePtr (AddedVariable, AuthFor= mat); > + NameSize =3D NameSizeOfVariable (AddedVariable, AuthFor= mat); > + if (CompareGuid ( > + GetVendorGuidPtr (AddedVariable, AuthFormat), > + GetVendorGuidPtr (Variable, AuthFormat) > + ) && (NameSize =3D=3D NameSizeOfVariable (Variable, AuthFo= rmat))) > + { > + Point0 =3D (VOID *)GetVariableNamePtr (AddedVariable, AuthForm= at); > + Point1 =3D (VOID *)GetVariableNamePtr (Variable, AuthFormat); > + if (CompareMem (Point0, Point1, NameSize) =3D=3D 0) { > + FoundAdded =3D TRUE; > + break; > + } > + } > + > + AddedVariable =3D NextAddedVariable; > + } > + > + if (!FoundAdded) { > + // > + // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED. > + // > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize); > + ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; > + if (!IsVolatile) { > + (VOID)ProtectedVariableLibRefresh ( > + (VARIABLE_HEADER *)CurrPtr, > + VariableSize, > + (UINTN)CurrPtr - (UINTN)ValidBuffer, > + FALSE > + ); > + > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD= ) > + =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) > + { > + HwErrVariableTotalSize +=3D VariableSize; > + } else { > + CommonVariableTotalSize +=3D VariableSize; > + if (IsUserVariable (Variable)) { > + CommonUserVariableTotalSize +=3D VariableSize; > + } > + } > + } > + > + CurrPtr +=3D VariableSize; > + } > + } > + > + Variable =3D NextVariable; > + } > + > + // > + // Install the new variable if it is not NULL. > + // > + if (NewVariable !=3D NULL) { > + if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > > VariableStoreHeader->Size) { > + // > + // No enough space to store the new variable. > + // > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + if (!IsVolatile) { > + if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) > =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + HwErrVariableTotalSize +=3D NewVariableSize; > + } else if ((NewVariable->Attributes & > EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + CommonVariableTotalSize +=3D NewVariableSize; > + if (IsUserVariable (NewVariable)) { > + CommonUserVariableTotalSize +=3D NewVariableSize; > + } > + } > + > + if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) || > + (CommonVariableTotalSize > mVariableModuleGlobal- > >CommonVariableSpace) || > + (CommonUserVariableTotalSize > mVariableModuleGlobal- > >CommonMaxUserVariableSpace)) > + { > + // > + // No enough space to store the new variable by NV or NV+HR attr= ibute. > + // > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + } > + > + CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize); > + ((VARIABLE_HEADER *)CurrPtr)->State =3D VAR_ADDED; > + if (UpdatingVariable !=3D NULL) { > + UpdatingPtrTrack->CurrPtr =3D (VARIABLE_HEADER > *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - > (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer))); > + UpdatingPtrTrack->InDeletedTransitionPtr =3D NULL; > + } > + > + CurrPtr +=3D NewVariableSize; > + } > + > + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + // > + // If volatile/emulated non-volatile variable store, just copy valid= buffer. > + // > + SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xf= f); > + CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - > (UINTN)ValidBuffer); > + *LastVariableOffset =3D (UINTN)CurrPtr - (UINTN)ValidBuffer; > + if (!IsVolatile) { > + // > + // Emulated non-volatile variable mode. > + // > + mVariableModuleGlobal->HwErrVariableTotalSize =3D > HwErrVariableTotalSize; > + mVariableModuleGlobal->CommonVariableTotalSize =3D > CommonVariableTotalSize; > + mVariableModuleGlobal->CommonUserVariableTotalSize =3D > CommonUserVariableTotalSize; > + } > + > + Status =3D EFI_SUCCESS; > + } else { > + // > + // If non-volatile variable store, perform FTW here. > + // > + Status =3D FtwVariableSpace ( > + VariableBase, > + (VARIABLE_STORE_HEADER *)ValidBuffer > + ); > + if (!EFI_ERROR (Status)) { > + *LastVariableOffset =3D (UINTN)Curr= Ptr - (UINTN)ValidBuffer; > + mVariableModuleGlobal->HwErrVariableTotalSize =3D > HwErrVariableTotalSize; > + mVariableModuleGlobal->CommonVariableTotalSize =3D > CommonVariableTotalSize; > + mVariableModuleGlobal->CommonUserVariableTotalSize =3D > CommonUserVariableTotalSize; > + } else { > + mVariableModuleGlobal->HwErrVariableTotalSize =3D 0; > + mVariableModuleGlobal->CommonVariableTotalSize =3D 0; > + mVariableModuleGlobal->CommonUserVariableTotalSize =3D 0; > + Variable =3D GetStartPoi= nter > ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase); > + while (IsValidVariableHeader (Variable, GetEndPointer > ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase), AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (Variable, AuthFormat); > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) > =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + mVariableModuleGlobal->HwErrVariableTotalSize +=3D VariableSiz= e; > + } else if ((Variable->Attributes & > EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + mVariableModuleGlobal->CommonVariableTotalSize +=3D VariableSi= ze; > + if (IsUserVariable (Variable)) { > + mVariableModuleGlobal->CommonUserVariableTotalSize +=3D > VariableSize; > + } > + } > + > + Variable =3D NextVariable; > + } > + > + *LastVariableOffset =3D (UINTN)Variable - (UINTN)VariableBase; > + } > + } > + > +Done: > + DoneStatus =3D EFI_SUCCESS; > + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + DoneStatus =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache, > + 0, > + VariableStoreHeader->Size > + ); > + ASSERT_EFI_ERROR (DoneStatus); > + FreePool (ValidBuffer); > + } else { > + // > + // For NV variable reclaim, we use mNvVariableCache as the buffer, s= o copy > the data back. > + // > + CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, > VariableStoreHeader->Size); > + DoneStatus =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + 0, > + VariableStoreHeader->Size > + ); > + ASSERT_EFI_ERROR (DoneStatus); > + } > + > + if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) { > + Status =3D DoneStatus; > + } > + > + return Status; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.c > new file mode 100644 > index 000000000000..b2bcb97932ba > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/RuntimeDxeUnitT > est/VariableLockRequestToLockUnitTest.c > @@ -0,0 +1,607 @@ > +/** @file > + This is a host-based unit test for the VariableLockRequestToLock shim. > + > + Copyright (c) Microsoft Corporation. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#define UNIT_TEST_NAME "VarPol/VarLock Shim Unit Test" > +#define UNIT_TEST_VERSION "1.0" > + > +/// =3D=3D=3D CODE UNDER TEST > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +EFI_STATUS > +EFIAPI > +VariableLockRequestToLock ( > + IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ); > + > +/// =3D=3D=3D TEST DATA > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +// > +// Test GUID 1 {F955BA2D-4A2C-480C-BFD1-3CC522610592} > +// > +EFI_GUID mTestGuid1 =3D { > + 0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5,= 0x92 } > +}; > + > +// > +// Test GUID 2 {2DEA799E-5E73-43B9-870E-C945CE82AF3A} > +// > +EFI_GUID mTestGuid2 =3D { > + 0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf,= 0x3a } > +}; > + > +// > +// Test GUID 3 {698A2BFD-A616-482D-B88C-7100BD6682A9} > +// > +EFI_GUID mTestGuid3 =3D { > + 0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82,= 0xa9 } > +}; > + > +#define TEST_VAR_1_NAME L"TestVar1" > +#define TEST_VAR_2_NAME L"TestVar2" > +#define TEST_VAR_3_NAME L"TestVar3" > + > +#define TEST_POLICY_ATTRIBUTES_NULL 0 > +#define TEST_POLICY_MIN_SIZE_NULL 0 > +#define TEST_POLICY_MAX_SIZE_NULL MAX_UINT32 > + > +#define TEST_POLICY_MIN_SIZE_10 10 > +#define TEST_POLICY_MAX_SIZE_200 200 > + > +/// =3D=3D=3D HELPER FUNCTIONS > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +/** > + Mocked version of GetVariable, for testing. > + > + @param VariableName > + @param VendorGuid > + @param Attributes > + @param DataSize > + @param Data > +**/ > +EFI_STATUS > +EFIAPI > +StubGetVariableNull ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + UINT32 MockedAttr; > + UINTN MockedDataSize; > + VOID *MockedData; > + EFI_STATUS MockedReturn; > + > + check_expected_ptr (VariableName); > + check_expected_ptr (VendorGuid); > + check_expected_ptr (DataSize); > + > + MockedAttr =3D (UINT32)mock (); > + MockedDataSize =3D (UINTN)mock (); > + MockedData =3D (VOID *)(UINTN)mock (); > + MockedReturn =3D (EFI_STATUS)mock (); > + > + if (Attributes !=3D NULL) { > + *Attributes =3D MockedAttr; > + } > + > + if ((Data !=3D NULL) && !EFI_ERROR (MockedReturn)) { > + CopyMem (Data, MockedData, MockedDataSize); > + } > + > + *DataSize =3D MockedDataSize; > + > + return MockedReturn; > +} > + > +// > +// Anything you think might be helpful that isn't a test itself. > +// > + > +/** > + This is a common setup function that will ensure the library is always > + initialized with the stubbed GetVariable. > + > + Not used by all test cases, but by most. > + > + @param[in] Context Unit test case context > +**/ > +STATIC > +UNIT_TEST_STATUS > +EFIAPI > +LibInitMocked ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? > UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED; > +} > + > +/** > + Common cleanup function to make sure that the library is always de-ini= tialized > + prior to the next test case. > + > + @param[in] Context Unit test case context > +**/ > +STATIC > +VOID > +EFIAPI > +LibCleanup ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + DeinitVariablePolicyLib (); > +} > + > +/// =3D=3D=3D TEST CASES > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +/// =3D=3D=3D=3D=3D SHIM SUITE > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +/** > + Test Case that locks a single variable using the Variable Lock Protoco= l. > + The call is expected to succeed. > + > + @param[in] Context Unit test case context > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingWithoutAnyPoliciesShouldSucceed ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks the same variable twice using the Variable Lock P= rotocol. > + Both calls are expected to succeed. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingTwiceShouldSucceed ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks a variable using the Variable Policy Protocol the= n locks > + the same variable using the Variable Lock Protocol. > + Both calls are expected to succeed. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingALockedVariableShouldSucceed ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewEntry; > + > + // > + // Create a variable policy that locks the variable. > + // > + Status =3D CreateBasicVariablePolicy ( > + &mTestGuid1, > + TEST_VAR_1_NAME, > + TEST_POLICY_MIN_SIZE_NULL, > + TEST_POLICY_MAX_SIZE_200, > + TEST_POLICY_ATTRIBUTES_NULL, > + TEST_POLICY_ATTRIBUTES_NULL, > + VARIABLE_POLICY_TYPE_LOCK_NOW, > + &NewEntry > + ); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // > + // Register the new policy. > + // > + Status =3D RegisterVariablePolicy (NewEntry); > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + FreePool (NewEntry); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks a variable using the Variable Policy Protocol wit= h a > + policy other than LOCK_NOW then attempts to lock the same variable usi= ng > the > + Variable Lock Protocol. The call to Variable Policy is expected to su= cceed > + and the call to Variable Lock is expected to fail. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingAnUnlockedVariableShouldFail ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewEntry; > + > + // Create a variable policy that locks the variable. > + Status =3D CreateVarStateVariablePolicy ( > + &mTestGuid1, > + TEST_VAR_1_NAME, > + TEST_POLICY_MIN_SIZE_NULL, > + TEST_POLICY_MAX_SIZE_200, > + TEST_POLICY_ATTRIBUTES_NULL, > + TEST_POLICY_ATTRIBUTES_NULL, > + &mTestGuid2, > + 1, > + TEST_VAR_2_NAME, > + &NewEntry > + ); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // Register the new policy. > + Status =3D RegisterVariablePolicy (NewEntry); > + > + // Configure the stub to not care about parameters. We're testing erro= rs. > + expect_any_always (StubGetVariableNull, VariableName); > + expect_any_always (StubGetVariableNull, VendorGuid); > + expect_any_always (StubGetVariableNull, DataSize); > + > + // With a policy, make sure that writes still work, since the variable= doesn't > exist. > + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // > Attributes > + will_return (StubGetVariableNull, 0); //= Size > + will_return (StubGetVariableNull, (UINTN)NULL); //= DataPtr > + will_return (StubGetVariableNull, EFI_NOT_FOUND); //= Status > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_TRUE (EFI_ERROR (Status)); > + > + FreePool (NewEntry); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks a variable using the Variable Policy Protocol wit= h a > + policy other than LOCK_NOW, but is currently locked. Then attempts to= lock > + the same variable using the Variable Lock Protocol. The call to Varia= ble > + Policy is expected to succeed and the call to Variable Lock also expec= ted to > + succeed. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingALockedVariableWithMatchingDataShouldSucceed ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewEntry; > + UINT8 Data; > + > + // Create a variable policy that locks the variable. > + Status =3D CreateVarStateVariablePolicy ( > + &mTestGuid1, > + TEST_VAR_1_NAME, > + TEST_POLICY_MIN_SIZE_NULL, > + TEST_POLICY_MAX_SIZE_200, > + TEST_POLICY_ATTRIBUTES_NULL, > + TEST_POLICY_ATTRIBUTES_NULL, > + &mTestGuid2, > + 1, > + TEST_VAR_2_NAME, > + &NewEntry > + ); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // Register the new policy. > + Status =3D RegisterVariablePolicy (NewEntry); > + > + // Configure the stub to not care about parameters. We're testing erro= rs. > + expect_any_always (StubGetVariableNull, VariableName); > + expect_any_always (StubGetVariableNull, VendorGuid); > + expect_any_always (StubGetVariableNull, DataSize); > + > + // With a policy, make sure that writes still work, since the variable= doesn't > exist. > + Data =3D 1; > + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // > Attributes > + will_return (StubGetVariableNull, sizeof (Data)); //= Size > + will_return (StubGetVariableNull, (UINTN)&Data); //= DataPtr > + will_return (StubGetVariableNull, EFI_SUCCESS); //= Status > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_TRUE (!EFI_ERROR (Status)); > + > + FreePool (NewEntry); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks a variable using the Variable Policy Protocol wit= h a > + policy other than LOCK_NOW, but variable data does not match. Then > attempts > + to lock the same variable using the Variable Lock Protocol. The call = to > + Variable Policy is expected to succeed and the call to Variable Lock i= s > + expected to fail. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +LockingALockedVariableWithNonMatchingDataShouldFail ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewEntry; > + UINT8 Data; > + > + // Create a variable policy that locks the variable. > + Status =3D CreateVarStateVariablePolicy ( > + &mTestGuid1, > + TEST_VAR_1_NAME, > + TEST_POLICY_MIN_SIZE_NULL, > + TEST_POLICY_MAX_SIZE_200, > + TEST_POLICY_ATTRIBUTES_NULL, > + TEST_POLICY_ATTRIBUTES_NULL, > + &mTestGuid2, > + 1, > + TEST_VAR_2_NAME, > + &NewEntry > + ); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // Register the new policy. > + Status =3D RegisterVariablePolicy (NewEntry); > + > + // Configure the stub to not care about parameters. We're testing erro= rs. > + expect_any_always (StubGetVariableNull, VariableName); > + expect_any_always (StubGetVariableNull, VendorGuid); > + expect_any_always (StubGetVariableNull, DataSize); > + > + // With a policy, make sure that writes still work, since the variable= doesn't > exist. > + Data =3D 2; > + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // > Attributes > + will_return (StubGetVariableNull, sizeof (Data)); //= Size > + will_return (StubGetVariableNull, (UINTN)&Data); //= DataPtr > + will_return (StubGetVariableNull, EFI_SUCCESS); //= Status > + > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_TRUE (EFI_ERROR (Status)); > + > + FreePool (NewEntry); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Test Case that locks a variable using Variable Lock Protocol Policy Pr= otocol > + then and then attempts to lock the same variable using the Variable Po= licy > + Protocol. The call to Variable Lock is expected to succeed and the ca= ll to > + Variable Policy is expected to fail. > + > + @param[in] Context Unit test case context > + **/ > +UNIT_TEST_STATUS > +EFIAPI > +SettingPolicyForALockedVariableShouldFail ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewEntry; > + > + // Lock the variable. > + Status =3D VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, > &mTestGuid1); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // Create a variable policy that locks the variable. > + Status =3D CreateVarStateVariablePolicy ( > + &mTestGuid1, > + TEST_VAR_1_NAME, > + TEST_POLICY_MIN_SIZE_NULL, > + TEST_POLICY_MAX_SIZE_200, > + TEST_POLICY_ATTRIBUTES_NULL, > + TEST_POLICY_ATTRIBUTES_NULL, > + &mTestGuid2, > + 1, > + TEST_VAR_2_NAME, > + &NewEntry > + ); > + UT_ASSERT_NOT_EFI_ERROR (Status); > + > + // Register the new policy. > + Status =3D RegisterVariablePolicy (NewEntry); > + UT_ASSERT_TRUE (EFI_ERROR (Status)); > + > + FreePool (NewEntry); > + > + return UNIT_TEST_PASSED; > +} > + > +/** > + Main entry point to this unit test application. > + > + Sets up and runs the test suites. > +**/ > +VOID > +EFIAPI > +UnitTestMain ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UNIT_TEST_FRAMEWORK_HANDLE Framework; > + UNIT_TEST_SUITE_HANDLE ShimTests; > + > + Framework =3D NULL; > + > + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, > UNIT_TEST_VERSION)); > + > + // > + // Start setting up the test framework for running the tests. > + // > + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_NAME, > gEfiCallerBaseName, UNIT_TEST_VERSION); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r= \n", > Status)); > + goto EXIT; > + } > + > + // > + // Add all test suites and tests. > + // > + Status =3D CreateUnitTestSuite ( > + &ShimTests, > + Framework, > + "Variable Lock Shim Tests", > + "VarPolicy.VarLockShim", > + NULL, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ShimTests\n"= )); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto EXIT; > + } > + > + AddTestCase ( > + ShimTests, > + "Locking a variable with no matching policies should always work", > + "EmptyPolicies", > + LockingWithoutAnyPoliciesShouldSucceed, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Locking a variable twice should always work", > + "DoubleLock", > + LockingTwiceShouldSucceed, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Locking a variable that's already locked by another policy should w= ork", > + "LockAfterPolicy", > + LockingALockedVariableShouldSucceed, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Locking a variable that already has an unlocked policy should fail"= , > + "LockAfterUnlockedPolicy", > + LockingAnUnlockedVariableShouldFail, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Locking a variable that already has an locked policy should succeed= ", > + "LockAfterLockedPolicyMatchingData", > + LockingALockedVariableWithMatchingDataShouldSucceed, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Locking a variable that already has an locked policy with matching = data > should succeed", > + "LockAfterLockedPolicyNonMatchingData", > + LockingALockedVariableWithNonMatchingDataShouldFail, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + AddTestCase ( > + ShimTests, > + "Adding a policy for a variable that has previously been locked shou= ld always > fail", > + "SetPolicyAfterLock", > + SettingPolicyForALockedVariableShouldFail, > + LibInitMocked, > + LibCleanup, > + NULL > + ); > + > + // > + // Execute the tests. > + // > + Status =3D RunAllTestSuites (Framework); > + > +EXIT: > + if (Framework !=3D NULL) { > + FreeUnitTestFramework (Framework); > + } > + > + return; > +} > + > +/// > +/// Avoid ECC error for function name that starts with lower case letter > +/// > +#define Main main > + > +/** > + Standard POSIX C entry point for host based unit test execution. > + > + @param[in] Argc Number of arguments > + @param[in] Argv Array of pointers to arguments > + > + @retval 0 Success > + @retval other Error > +**/ > +INT32 > +Main ( > + IN INT32 Argc, > + IN CHAR8 *Argv[] > + ) > +{ > + UnitTestMain (); > + return 0; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rDxe.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rDxe.c > new file mode 100644 > index 000000000000..b219ea9ec074 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rDxe.c > @@ -0,0 +1,27 @@ > +/** @file > + Barrier to stop speculative execution (DXE version). > + > +Copyright (c) 2018, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > + > +/** > + This service is consumed by the variable modules to place a barrier to= stop > + speculative execution. > + > + Ensures that no later instruction will execute speculatively, until al= l prior > + instructions have completed. > + > +**/ > +VOID > +VariableSpeculationBarrier ( > + VOID > + ) > +{ > + // > + // Do nothing. > + // > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rSmm.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rSmm.c > new file mode 100644 > index 000000000000..7107c042928e > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/SpeculationBarrie > rSmm.c > @@ -0,0 +1,26 @@ > +/** @file > + Barrier to stop speculative execution (SMM version). > + > +Copyright (c) 2018, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include "Variable.h" > + > +/** > + This service is consumed by the variable modules to place a barrier to= stop > + speculative execution. > + > + Ensures that no later instruction will execute speculatively, until al= l prior > + instructions have completed. > + > +**/ > +VOID > +VariableSpeculationBarrier ( > + VOID > + ) > +{ > + SpeculationBarrier (); > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c > new file mode 100644 > index 000000000000..88984c31ab4f > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockDxe.c > @@ -0,0 +1,153 @@ > +/** @file > + TCG MOR (Memory Overwrite Request) Lock Control support (DXE version). > + > + This module clears MemoryOverwriteRequestControlLock variable to indic= ate > + MOR lock control unsupported. > + > +Copyright (c) 2016, Intel Corporation. All rights reserved.
> +Copyright (c) Microsoft Corporation. > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include "Variable.h" > + > +#include > +#include > + > +/** > + This service is an MOR/MorLock checker handler for the SetVariable(). > + > + @param[in] VariableName the name of the vendor's variable, as a > + Null-Terminated Unicode String > + @param[in] VendorGuid Unify identifier for vendor. > + @param[in] Attributes Attributes bitmask to set for the variable. > + @param[in] DataSize The size in bytes of Data-Buffer. > + @param[in] Data Point to the content of the variable. > + > + @retval EFI_SUCCESS The MOR/MorLock check pass, and Variab= le > + driver can store the variable data. > + @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or > + attributes is not allowed for MOR vari= able. > + @retval EFI_ACCESS_DENIED The MOR/MorLock is locked. > + @retval EFI_ALREADY_STARTED The MorLock variable is handled inside= this > + function. Variable driver can just ret= urn > + EFI_SUCCESS. > +**/ > +EFI_STATUS > +SetVariableCheckHandlerMor ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + // > + // Just let it pass. No need provide protection for DXE version. > + // > + return EFI_SUCCESS; > +} > + > +/** > + Initialization for MOR Control Lock. > + > + @retval EFI_SUCCESS MorLock initialization success. > + @return Others Some error occurs. > +**/ > +EFI_STATUS > +MorLockInit ( > + VOID > + ) > +{ > + // > + // Always clear variable to report unsupported to OS. > + // The reason is that the DXE version is not proper to provide *protec= tion*. > + // BIOS should use SMM version variable driver to provide such capabil= ity. > + // > + VariableServiceSetVariable ( > + MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > + &gEfiMemoryOverwriteRequestControlLockGuid, > + 0, // Attributes > + 0, // DataSize > + NULL // Data > + ); > + > + // > + // The MOR variable can effectively improve platform security only whe= n the > + // MorLock variable protects the MOR variable. In turn MorLock cannot = be > made > + // secure without SMM support in the platform firmware (see above). > + // > + // Thus, delete the MOR variable, should it exist for any reason (some= OSes > + // are known to create MOR unintentionally, in an attempt to set it), = then > + // also lock the MOR variable, in order to prevent other modules from > + // creating it. > + // > + VariableServiceSetVariable ( > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > + &gEfiMemoryOverwriteControlDataGuid, > + 0, // Attributes > + 0, // DataSize > + NULL // Data > + ); > + > + return EFI_SUCCESS; > +} > + > +/** > + Delayed initialization for MOR Control Lock at EndOfDxe. > + > + This function performs any operations queued by MorLockInit(). > +**/ > +VOID > +MorLockInitAtEndOfDxe ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy; > + > + // First, we obviously need to locate the VariablePolicy protocol. > + Status =3D gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NUL= L, > (VOID **)&VariablePolicy); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Could not locate VariablePolicy > protocol! %r\n", __FUNCTION__, Status)); > + return; > + } > + > + // If we're successful, go ahead and set the policies to protect the t= arget > variables. > + Status =3D RegisterBasicVariablePolicy ( > + VariablePolicy, > + &gEfiMemoryOverwriteRequestControlLockGuid, > + MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > + VARIABLE_POLICY_NO_MIN_SIZE, > + VARIABLE_POLICY_NO_MAX_SIZE, > + VARIABLE_POLICY_NO_MUST_ATTR, > + VARIABLE_POLICY_NO_CANT_ATTR, > + VARIABLE_POLICY_TYPE_LOCK_NOW > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Could not lock variable %s! %r\n", > __FUNCTION__, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > Status)); > + } > + > + Status =3D RegisterBasicVariablePolicy ( > + VariablePolicy, > + &gEfiMemoryOverwriteControlDataGuid, > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > + VARIABLE_POLICY_NO_MIN_SIZE, > + VARIABLE_POLICY_NO_MAX_SIZE, > + VARIABLE_POLICY_NO_MUST_ATTR, > + VARIABLE_POLICY_NO_CANT_ATTR, > + VARIABLE_POLICY_TYPE_LOCK_NOW > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Could not lock variable %s! %r\n", > __FUNCTION__, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, Status)); > + } > + > + return; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm. > c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm. > c > new file mode 100644 > index 000000000000..296afd2ec414 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/TcgMorLockSmm. > c > @@ -0,0 +1,569 @@ > +/** @file > + TCG MOR (Memory Overwrite Request) Lock Control support (SMM version). > + > + This module initilizes MemoryOverwriteRequestControlLock variable. > + This module adds Variable Hook and check > MemoryOverwriteRequestControlLock. > + > +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
> +Copyright (c) Microsoft Corporation. > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include "Variable.h" > + > +#include > +#include > +#include > + > +typedef struct { > + CHAR16 *VariableName; > + EFI_GUID *VendorGuid; > +} VARIABLE_TYPE; > + > +VARIABLE_TYPE mMorVariableType[] =3D { > + { MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > &gEfiMemoryOverwriteControlDataGuid }, > + { MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > &gEfiMemoryOverwriteRequestControlLockGuid }, > +}; > + > +BOOLEAN mMorPassThru =3D FALSE; > + > +#define MOR_LOCK_DATA_UNLOCKED 0x0 > +#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1 > +#define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2 > + > +#define MOR_LOCK_V1_SIZE 1 > +#define MOR_LOCK_V2_KEY_SIZE 8 > + > +typedef enum { > + MorLockStateUnlocked =3D 0, > + MorLockStateLocked =3D 1, > +} MOR_LOCK_STATE; > + > +BOOLEAN mMorLockInitializationRequired =3D FALSE; > +UINT8 mMorLockKey[MOR_LOCK_V2_KEY_SIZE]; > +BOOLEAN mMorLockKeyEmpty =3D TRUE; > +BOOLEAN mMorLockPassThru =3D FALSE; > +MOR_LOCK_STATE mMorLockState =3D MorLockStateUnlocked; > + > +/** > + Returns if this is MOR related variable. > + > + @param VariableName the name of the vendor's variable, it's a Null- > Terminated Unicode String > + @param VendorGuid Unify identifier for vendor. > + > + @retval TRUE The variable is MOR related. > + @retval FALSE The variable is NOT MOR related. > +**/ > +BOOLEAN > +IsAnyMorVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + UINTN Index; > + > + for (Index =3D 0; Index < sizeof (mMorVariableType)/sizeof > (mMorVariableType[0]); Index++) { > + if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) =3D= =3D 0) > && > + (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) > + { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + Returns if this is MOR lock variable. > + > + @param VariableName the name of the vendor's variable, it's a Null- > Terminated Unicode String > + @param VendorGuid Unify identifier for vendor. > + > + @retval TRUE The variable is MOR lock variable. > + @retval FALSE The variable is NOT MOR lock variable. > +**/ > +BOOLEAN > +IsMorLockVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + if ((StrCmp (VariableName, > MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) =3D=3D 0) && > + (CompareGuid (VendorGuid, > &gEfiMemoryOverwriteRequestControlLockGuid))) > + { > + return TRUE; > + } > + > + return FALSE; > +} > + > +/** > + Set MOR lock variable. > + > + @param Data MOR Lock variable data. > + > + @retval EFI_SUCCESS The firmware has successfully stored t= he variable > and its data as > + defined by the Attributes. > + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bi= ts > was supplied, or the > + DataSize exceeds the maximum allowed. > + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode strin= g. > + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hol= d > the variable and its data. > + @retval EFI_DEVICE_ERROR The variable could not be saved due to= a > hardware failure. > + @retval EFI_WRITE_PROTECTED The variable in question is read-only. > + @retval EFI_WRITE_PROTECTED The variable in question cannot be del= eted. > + @retval EFI_SECURITY_VIOLATION The variable could not be written due = to > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS > + set but the AuthInfo does NOT pass the= validation check > carried > + out by the firmware. > + @retval EFI_NOT_FOUND The variable trying to be updated or d= eleted > was not found. > +**/ > +EFI_STATUS > +SetMorLockVariable ( > + IN UINT8 Data > + ) > +{ > + EFI_STATUS Status; > + > + mMorLockPassThru =3D TRUE; > + Status =3D VariableServiceSetVariable ( > + MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > + &gEfiMemoryOverwriteRequestControlLockGuid, > + EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, > + sizeof (Data), > + &Data > + ); > + mMorLockPassThru =3D FALSE; > + return Status; > +} > + > +/** > + This service is an MorLock checker handler for the SetVariable(). > + > + @param VariableName the name of the vendor's variable, as a > + Null-Terminated Unicode String > + @param VendorGuid Unify identifier for vendor. > + @param Attributes Point to memory location to return the attributes= of > variable. If the point > + is NULL, the parameter would be ignored. > + @param DataSize The size in bytes of Data-Buffer. > + @param Data Point to the content of the variable. > + > + @retval EFI_SUCCESS The MorLock check pass, and Variable d= river can > store the variable data. > + @retval EFI_INVALID_PARAMETER The MorLock data or data size or > attributes is not allowed. > + @retval EFI_ACCESS_DENIED The MorLock is locked. > + @retval EFI_WRITE_PROTECTED The MorLock deletion is not allowed. > + @retval EFI_ALREADY_STARTED The MorLock variable is handled inside= this > function. > + Variable driver can just return EFI_SU= CCESS. > +**/ > +EFI_STATUS > +SetVariableCheckHandlerMorLock ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Basic Check > + // > + if ((Attributes =3D=3D 0) || (DataSize =3D=3D 0) || (Data =3D=3D NULL)= ) { > + // > + // Permit deletion for passthru request, deny it otherwise. > + // > + return mMorLockPassThru ? EFI_SUCCESS : EFI_WRITE_PROTECTED; > + } > + > + if ((Attributes !=3D (EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) || > + ((DataSize !=3D MOR_LOCK_V1_SIZE) && (DataSize !=3D > MOR_LOCK_V2_KEY_SIZE))) > + { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Do not check if the request is passthru. > + // > + if (mMorLockPassThru) { > + return EFI_SUCCESS; > + } > + > + if (mMorLockState =3D=3D MorLockStateUnlocked) { > + // > + // In Unlocked State > + // > + if (DataSize =3D=3D MOR_LOCK_V1_SIZE) { > + // > + // V1 - lock permanently > + // > + if (*(UINT8 *)Data =3D=3D MOR_LOCK_DATA_UNLOCKED) { > + // > + // Unlock > + // > + Status =3D SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED); > + if (!EFI_ERROR (Status)) { > + // > + // return EFI_ALREADY_STARTED to skip variable set. > + // > + return EFI_ALREADY_STARTED; > + } else { > + // > + // SetVar fail > + // > + return Status; > + } > + } else if (*(UINT8 *)Data =3D=3D MOR_LOCK_DATA_LOCKED_WITHOUT_KEY)= { > + // > + // Lock without key > + // > + Status =3D SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY)= ; > + if (!EFI_ERROR (Status)) { > + // > + // Lock success > + // > + mMorLockState =3D MorLockStateLocked; > + // > + // return EFI_ALREADY_STARTED to skip variable set. > + // > + return EFI_ALREADY_STARTED; > + } else { > + // > + // SetVar fail > + // > + return Status; > + } > + } else { > + return EFI_INVALID_PARAMETER; > + } > + } else if (DataSize =3D=3D MOR_LOCK_V2_KEY_SIZE) { > + // > + // V2 lock and provision the key > + // > + > + // > + // Need set here because the data value on flash is different > + // > + Status =3D SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY); > + if (EFI_ERROR (Status)) { > + // > + // SetVar fail, do not provision the key > + // > + return Status; > + } else { > + // > + // Lock success, provision the key > + // > + mMorLockKeyEmpty =3D FALSE; > + CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE); > + mMorLockState =3D MorLockStateLocked; > + // > + // return EFI_ALREADY_STARTED to skip variable set. > + // > + return EFI_ALREADY_STARTED; > + } > + } else { > + ASSERT (FALSE); > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + // > + // In Locked State > + // > + if (mMorLockKeyEmpty || (DataSize !=3D MOR_LOCK_V2_KEY_SIZE)) { > + return EFI_ACCESS_DENIED; > + } > + > + if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) =3D=3D 0))= { > + // > + // Key match - unlock > + // > + > + // > + // Need set here because the data value on flash is different > + // > + Status =3D SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED); > + if (EFI_ERROR (Status)) { > + // > + // SetVar fail > + // > + return Status; > + } else { > + // > + // Unlock Success > + // > + mMorLockState =3D MorLockStateUnlocked; > + mMorLockKeyEmpty =3D TRUE; > + ZeroMem (mMorLockKey, sizeof (mMorLockKey)); > + // > + // return EFI_ALREADY_STARTED to skip variable set. > + // > + return EFI_ALREADY_STARTED; > + } > + } else { > + // > + // Key mismatch - Prevent Dictionary Attack > + // > + mMorLockState =3D MorLockStateLocked; > + mMorLockKeyEmpty =3D TRUE; > + ZeroMem (mMorLockKey, sizeof (mMorLockKey)); > + return EFI_ACCESS_DENIED; > + } > + } > +} > + > +/** > + This service is an MOR/MorLock checker handler for the SetVariable(). > + > + @param[in] VariableName the name of the vendor's variable, as a > + Null-Terminated Unicode String > + @param[in] VendorGuid Unify identifier for vendor. > + @param[in] Attributes Attributes bitmask to set for the variable. > + @param[in] DataSize The size in bytes of Data-Buffer. > + @param[in] Data Point to the content of the variable. > + > + @retval EFI_SUCCESS The MOR/MorLock check pass, and Variab= le > + driver can store the variable data. > + @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or > + attributes is not allowed for MOR vari= able. > + @retval EFI_ACCESS_DENIED The MOR/MorLock is locked. > + @retval EFI_ALREADY_STARTED The MorLock variable is handled inside= this > + function. Variable driver can just ret= urn > + EFI_SUCCESS. > +**/ > +EFI_STATUS > +SetVariableCheckHandlerMor ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + // > + // do not handle non-MOR variable > + // > + if (!IsAnyMorVariable (VariableName, VendorGuid)) { > + return EFI_SUCCESS; > + } > + > + // Permit deletion when policy is disabled. > + if (!IsVariablePolicyEnabled () && ((Attributes =3D=3D 0) || (DataSize= =3D=3D 0))) { > + return EFI_SUCCESS; > + } > + > + // > + // MorLock variable > + // > + if (IsMorLockVariable (VariableName, VendorGuid)) { > + return SetVariableCheckHandlerMorLock ( > + VariableName, > + VendorGuid, > + Attributes, > + DataSize, > + Data > + ); > + } > + > + // > + // Mor Variable > + // > + > + // > + // Permit deletion for passthru request. > + // > + if (((Attributes =3D=3D 0) || (DataSize =3D=3D 0)) && mMorPassThru) { > + return EFI_SUCCESS; > + } > + > + // > + // Basic Check > + // > + if ((Attributes !=3D (EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) || > + (DataSize !=3D sizeof (UINT8)) || > + (Data =3D=3D NULL)) > + { > + return EFI_INVALID_PARAMETER; > + } > + > + if (mMorLockState =3D=3D MorLockStateLocked) { > + // > + // If lock, deny access > + // > + return EFI_ACCESS_DENIED; > + } > + > + // > + // grant access > + // > + return EFI_SUCCESS; > +} > + > +/** > + Initialization for MOR Control Lock. > + > + @retval EFI_SUCCESS MorLock initialization success. > + @return Others Some error occurs. > +**/ > +EFI_STATUS > +MorLockInit ( > + VOID > + ) > +{ > + mMorLockInitializationRequired =3D TRUE; > + return EFI_SUCCESS; > +} > + > +/** > + Delayed initialization for MOR Control Lock at EndOfDxe. > + > + This function performs any operations queued by MorLockInit(). > +**/ > +VOID > +MorLockInitAtEndOfDxe ( > + VOID > + ) > +{ > + UINTN MorSize; > + EFI_STATUS MorStatus; > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewPolicy; > + > + if (!mMorLockInitializationRequired) { > + // > + // The EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL has never been > installed, thus > + // the variable write service is unavailable. This should never happ= en. > + // > + ASSERT (FALSE); > + return; > + } > + > + // > + // Check if the MOR variable exists. > + // > + MorSize =3D 0; > + MorStatus =3D VariableServiceGetVariable ( > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > + &gEfiMemoryOverwriteControlDataGuid, > + NULL, // Attributes > + &MorSize, > + NULL // Data > + ); > + // > + // We provided a zero-sized buffer, so the above call can never succee= d. > + // > + ASSERT (EFI_ERROR (MorStatus)); > + > + if (MorStatus =3D=3D EFI_BUFFER_TOO_SMALL) { > + // > + // The MOR variable exists. > + // > + // Some OSes don't follow the TCG's Platform Reset Attack Mitigation= spec > + // in that the OS should never create the MOR variable, only read an= d write > + // it -- these OSes (unintentionally) create MOR if the platform fir= mware > + // does not produce it. Whether this is the case (from the last OS b= oot) > + // can be deduced from the absence of the TCG / TCG2 protocols, as e= dk2's > + // MOR implementation depends on (one of) those protocols. > + // > + if (VariableHaveTcgProtocols ()) { > + // > + // The MOR variable originates from the platform firmware; set the= MOR > + // Control Lock variable to report the locking capability to the O= S. > + // > + SetMorLockVariable (0); > + return; > + } > + > + // > + // The MOR variable's origin is inexplicable; delete it. > + // > + DEBUG (( > + DEBUG_WARN, > + "%a: deleting unexpected / unsupported variable %g:%s\n", > + __FUNCTION__, > + &gEfiMemoryOverwriteControlDataGuid, > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME > + )); > + > + mMorPassThru =3D TRUE; > + VariableServiceSetVariable ( > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > + &gEfiMemoryOverwriteControlDataGuid, > + 0, // Attributes > + 0, // DataSize > + NULL // Data > + ); > + mMorPassThru =3D FALSE; > + } > + > + // > + // The MOR variable is absent; the platform firmware does not support = it. > + // Lock the variable so that no other module may create it. > + // > + NewPolicy =3D NULL; > + Status =3D CreateBasicVariablePolicy ( > + &gEfiMemoryOverwriteControlDataGuid, > + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, > + VARIABLE_POLICY_NO_MIN_SIZE, > + VARIABLE_POLICY_NO_MAX_SIZE, > + VARIABLE_POLICY_NO_MUST_ATTR, > + VARIABLE_POLICY_NO_CANT_ATTR, > + VARIABLE_POLICY_TYPE_LOCK_NOW, > + &NewPolicy > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D RegisterVariablePolicy (NewPolicy); > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", > __FUNCTION__, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, Status)); > + ASSERT_EFI_ERROR (Status); > + } > + > + if (NewPolicy !=3D NULL) { > + FreePool (NewPolicy); > + } > + > + // > + // Delete the MOR Control Lock variable too (should it exists for some > + // reason) and prevent other modules from creating it. > + // > + mMorLockPassThru =3D TRUE; > + VariableServiceSetVariable ( > + MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > + &gEfiMemoryOverwriteRequestControlLockGuid, > + 0, // Attributes > + 0, // DataSize > + NULL // Data > + ); > + mMorLockPassThru =3D FALSE; > + > + NewPolicy =3D NULL; > + Status =3D CreateBasicVariablePolicy ( > + &gEfiMemoryOverwriteRequestControlLockGuid, > + MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > + VARIABLE_POLICY_NO_MIN_SIZE, > + VARIABLE_POLICY_NO_MAX_SIZE, > + VARIABLE_POLICY_NO_MUST_ATTR, > + VARIABLE_POLICY_NO_CANT_ATTR, > + VARIABLE_POLICY_TYPE_LOCK_NOW, > + &NewPolicy > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D RegisterVariablePolicy (NewPolicy); > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", > __FUNCTION__, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, > Status)); > + ASSERT_EFI_ERROR (Status); > + } > + > + if (NewPolicy !=3D NULL) { > + FreePool (NewPolicy); > + } > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c > new file mode 100644 > index 000000000000..a94b0b02ec15 > --- /dev/null > +++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VarCheck.c > @@ -0,0 +1,101 @@ > +/** @file > + Implementation functions and structures for var check protocol > + and variable lock protocol based on VarCheckLib. > + > +Copyright (c) 2015, Intel Corporation. All rights reserved.
> +Copyright (c) Microsoft Corporation. > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > + > +/** > + Register SetVariable check handler. > + > + @param[in] Handler Pointer to check handler. > + > + @retval EFI_SUCCESS The SetVariable check handler was regist= ered > successfully. > + @retval EFI_INVALID_PARAMETER Handler is NULL. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > SetVariable check handler register request. > + @retval EFI_UNSUPPORTED This interface is not implemented. > + For example, it is unsupported in VarChe= ck protocol if both > VarCheck and SmmVarCheck protocols are present. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckRegisterSetVariableCheckHandler ( > + IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler > + ) > +{ > + EFI_STATUS Status; > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + Status =3D VarCheckLibRegisterSetVariableCheckHandler (Handler); > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + return Status; > +} > + > +/** > + Variable property set. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[in] VariableProperty Pointer to the input variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was set successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string, > + or the fields of VariableProperty are no= t valid. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > variable property set request. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertySet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ) > +{ > + EFI_STATUS Status; > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + Status =3D VarCheckLibVariablePropertySet (Name, Guid, VariablePropert= y); > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + return Status; > +} > + > +/** > + Variable property get. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[out] VariableProperty Pointer to the output variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was got successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string. > + @retval EFI_NOT_FOUND The property of variable specified by th= e Name > and Guid was not found. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertyGet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ) > +{ > + EFI_STATUS Status; > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + Status =3D VarCheckLibVariablePropertyGet (Name, Guid, VariablePropert= y); > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + return Status; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c > new file mode 100644 > index 000000000000..19b432b772d7 > --- /dev/null > +++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/Variable.c > @@ -0,0 +1,4037 @@ > +/** @file > + The common variable operation routines shared by DXE_RUNTIME variable > + module and DXE_SMM variable module. > + > + Caution: This module requires additional review when modified. > + This driver will have external input - variable data. They may be inpu= t in SMM > mode. > + This external input must be validated carefully to avoid security issu= e like > + buffer overflow, integer overflow. > + > + VariableServiceGetNextVariableName () and > VariableServiceQueryVariableInfo() are external API. > + They need check input parameter. > + > + VariableServiceGetVariable() and VariableServiceSetVariable() are exte= rnal API > + to receive datasize and data buffer. The size should be checked carefu= lly. > + > + VariableServiceSetVariable() should also check authenticate data to av= oid > buffer overflow, > + integer overflow. It should also check attribute to avoid authenticati= on bypass. > + > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP
> +Copyright (c) Microsoft Corporation.
> +Copyright (c) 2022, ARM Limited. All rights reserved.
> + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > +#include "VariableNonVolatile.h" > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal =3D NULL; > + > +/// > +/// Define a memory cache that improves the search performance for a > variable. > +/// For EmuNvMode =3D=3D TRUE, it will be equal to NonVolatileVariableBa= se. > +/// > +VARIABLE_STORE_HEADER *mNvVariableCache =3D NULL; > + > +/// > +/// Memory cache of Fv Header. > +/// > +EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache =3D NULL; > + > +/// > +/// The memory entry used for variable statistics data. > +/// > +VARIABLE_INFO_ENTRY *gVariableInfo =3D NULL; > + > +/// > +/// The flag to indicate whether the platform has left the DXE phase of > execution. > +/// > +BOOLEAN mEndOfDxe =3D FALSE; > + > +/// > +/// It indicates the var check request source. > +/// In the implementation, DXE is regarded as untrusted, and SMM is trus= ted. > +/// > +VAR_CHECK_REQUEST_SOURCE mRequestSource =3D VarCheckFromUntrusted; > + > +// > +// It will record the current boot error flag before EndOfDxe. > +// > +VAR_ERROR_FLAG mCurrentBootVarErrFlag =3D VAR_ERROR_FLAG_NO_ERROR; > + > +VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] =3D { > + { > + &gEdkiiVarErrorFlagGuid, > + VAR_ERROR_FLAG_NAME, > + { > + VAR_CHECK_VARIABLE_PROPERTY_REVISION, > + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, > + VARIABLE_ATTRIBUTE_NV_BS_RT, > + sizeof (VAR_ERROR_FLAG), > + sizeof (VAR_ERROR_FLAG) > + } > + }, > +}; > + > +AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn =3D { > + AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION, > + // > + // StructSize, TO BE FILLED > + // > + 0, > + // > + // MaxAuthVariableSize, TO BE FILLED > + // > + 0, > + VariableExLibFindVariable, > + VariableExLibFindNextVariable, > + VariableExLibUpdateVariable, > + VariableExLibGetScratchBuffer, > + VariableExLibCheckRemainingSpaceForConsistency, > + VariableExLibAtRuntime, > +}; > + > +AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut; > + > +/** > + > + This function writes data to the FWH at the correct LBA even if the LB= As > + are fragmented. > + > + @param Global Pointer to VARAIBLE_GLOBAL structure. > + @param Volatile Point out the Variable is Volatile or N= on-Volatile. > + @param SetByIndex TRUE if target pointer is given as inde= x. > + FALSE if target pointer is absolute. > + @param Fvb Pointer to the writable FVB protocol. > + @param DataPtrIndex Pointer to the Data from the end of > VARIABLE_STORE_HEADER > + structure. > + @param DataSize Size of data to be written. > + @param Buffer Pointer to the buffer from which data i= s written. > + > + @retval EFI_INVALID_PARAMETER Parameters not valid. > + @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable > update. > + @retval EFI_OUT_OF_RESOURCES The remaining size is not enough. > + @retval EFI_SUCCESS Variable store successfully updated. > + > +**/ > +EFI_STATUS > +UpdateVariableStore ( > + IN VARIABLE_GLOBAL *Global, > + IN BOOLEAN Volatile, > + IN BOOLEAN SetByIndex, > + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, > + IN UINTN DataPtrIndex, > + IN UINT32 DataSize, > + IN UINT8 *Buffer > + ) > +{ > + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; > + UINTN BlockIndex2; > + UINTN LinearOffset; > + UINTN CurrWriteSize; > + UINTN CurrWritePtr; > + UINT8 *CurrBuffer; > + EFI_LBA LbaNumber; > + UINTN Size; > + VARIABLE_STORE_HEADER *VolatileBase; > + EFI_PHYSICAL_ADDRESS FvVolHdr; > + EFI_PHYSICAL_ADDRESS DataPtr; > + EFI_STATUS Status; > + > + FvVolHdr =3D 0; > + DataPtr =3D DataPtrIndex; > + > + // > + // Check if the Data is Volatile. > + // > + if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) { > + if (Fvb =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + Status =3D Fvb->GetPhysicalAddress (Fvb, &FvVolHdr); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Data Pointer should point to the actual Address where data is to = be > + // written. > + // > + if (SetByIndex) { > + DataPtr +=3D mVariableModuleGlobal- > >VariableGlobal.NonVolatileVariableBase; > + } > + > + if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) = { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + // > + // Data Pointer should point to the actual Address where data is to = be > + // written. > + // > + if (Volatile) { > + VolatileBase =3D (VARIABLE_STORE_HEADER > *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); > + if (SetByIndex) { > + DataPtr +=3D mVariableModuleGlobal->VariableGlobal.VolatileVaria= bleBase; > + } > + > + if ((DataPtr + DataSize) > ((UINTN)VolatileBase + VolatileBase->Si= ze)) { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + // > + // Emulated non-volatile variable mode. > + // > + if (SetByIndex) { > + DataPtr +=3D (UINTN)mNvVariableCache; > + } > + > + if ((DataPtr + DataSize) > ((UINTN)mNvVariableCache + mNvVariableC= ache- > >Size)) { > + return EFI_OUT_OF_RESOURCES; > + } > + } > + > + // > + // If Volatile/Emulated Non-volatile Variable just do a simple mem c= opy. > + // > + CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize); > + return EFI_SUCCESS; > + } > + > + // > + // If we are here we are dealing with Non-Volatile Variables. > + // > + LinearOffset =3D (UINTN)FvVolHdr; > + CurrWritePtr =3D (UINTN)DataPtr; > + CurrWriteSize =3D DataSize; > + CurrBuffer =3D Buffer; > + LbaNumber =3D 0; > + > + if (CurrWritePtr < LinearOffset) { > + return EFI_INVALID_PARAMETER; > + } > + > + for (PtrBlockMapEntry =3D mNvFvHeaderCache->BlockMap; PtrBlockMapEntry= - > >NumBlocks !=3D 0; PtrBlockMapEntry++) { > + for (BlockIndex2 =3D 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; > BlockIndex2++) { > + // > + // Check to see if the Variable Writes are spanning through multip= le > + // blocks. > + // > + if ((CurrWritePtr >=3D LinearOffset) && (CurrWritePtr < LinearOffs= et + > PtrBlockMapEntry->Length)) { > + if ((CurrWritePtr + CurrWriteSize) <=3D (LinearOffset + PtrBlock= MapEntry- > >Length)) { > + Status =3D Fvb->Write ( > + Fvb, > + LbaNumber, > + (UINTN)(CurrWritePtr - LinearOffset), > + &CurrWriteSize, > + CurrBuffer > + ); > + return Status; > + } else { > + Size =3D (UINT32)(LinearOffset + PtrBlockMapEntry->Length - > CurrWritePtr); > + Status =3D Fvb->Write ( > + Fvb, > + LbaNumber, > + (UINTN)(CurrWritePtr - LinearOffset), > + &Size, > + CurrBuffer > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + CurrWritePtr =3D LinearOffset + PtrBlockMapEntry->Length; > + CurrBuffer =3D CurrBuffer + Size; > + CurrWriteSize =3D CurrWriteSize - Size; > + } > + } > + > + LinearOffset +=3D PtrBlockMapEntry->Length; > + LbaNumber++; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Record variable error flag. > + > + @param[in] Flag Variable error flag to record. > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Attributes Attributes of the variable. > + @param[in] VariableSize Size of the variable. > + > +**/ > +VOID > +RecordVarErrorFlag ( > + IN VAR_ERROR_FLAG Flag, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN VariableSize > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK Variable; > + VAR_ERROR_FLAG *VarErrFlag; > + VAR_ERROR_FLAG TempFlag; > + > + DEBUG_CODE_BEGIN (); > + DEBUG ((DEBUG_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - > 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize)); > + if (Flag =3D=3D VAR_ERROR_FLAG_SYSTEM_ERROR) { > + if (AtRuntime ()) { > + DEBUG ((DEBUG_ERROR, "CommonRuntimeVariableSpace =3D 0x%x - > CommonVariableTotalSize =3D 0x%x\n", mVariableModuleGlobal- > >CommonRuntimeVariableSpace, mVariableModuleGlobal- > >CommonVariableTotalSize)); > + } else { > + DEBUG ((DEBUG_ERROR, "CommonVariableSpace =3D 0x%x - > CommonVariableTotalSize =3D 0x%x\n", mVariableModuleGlobal- > >CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize)); > + } > + } else { > + DEBUG ((DEBUG_ERROR, "CommonMaxUserVariableSpace =3D 0x%x - > CommonUserVariableTotalSize =3D 0x%x\n", mVariableModuleGlobal- > >CommonMaxUserVariableSpace, mVariableModuleGlobal- > >CommonUserVariableTotalSize)); > + } > + > + DEBUG_CODE_END (); > + > + if (!mEndOfDxe) { > + // > + // Before EndOfDxe, just record the current boot variable error flag= to local > variable, > + // and leave the variable error flag in NV flash as the last boot va= riable error > flag. > + // After EndOfDxe in InitializeVarErrorFlag (), the variable error f= lag in NV > flash > + // will be initialized to this local current boot variable error fla= g. > + // > + mCurrentBootVarErrFlag &=3D Flag; > + return; > + } > + > + // > + // Record error flag (it should have be initialized). > + // > + Status =3D FindVariable ( > + VAR_ERROR_FLAG_NAME, > + &gEdkiiVarErrorFlagGuid, > + &Variable, > + &mVariableModuleGlobal->VariableGlobal, > + FALSE > + ); > + if (!EFI_ERROR (Status)) { > + VarErrFlag =3D (VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPt= r, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + TempFlag =3D *VarErrFlag; > + TempFlag &=3D Flag; > + if (TempFlag =3D=3D *VarErrFlag) { > + return; > + } > + > + Status =3D UpdateVariableStore ( > + &mVariableModuleGlobal->VariableGlobal, > + FALSE, > + FALSE, > + mVariableModuleGlobal->FvbInstance, > + (UINTN)VarErrFlag - (UINTN)mNvVariableCache + > (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, > + sizeof (TempFlag), > + &TempFlag > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Update the data in NV cache. > + // > + *VarErrFlag =3D TempFlag; > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache, > + 0, > + mNvVariableCache->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + } > +} > + > +/** > + Initialize variable error flag. > + > + Before EndOfDxe, the variable indicates the last boot variable error f= lag, > + then it means the last boot variable error flag must be got before End= OfDxe. > + After EndOfDxe, the variable indicates the current boot variable error= flag, > + then it means the current boot variable error flag must be got after E= ndOfDxe. > + > +**/ > +VOID > +InitializeVarErrorFlag ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK Variable; > + VAR_ERROR_FLAG Flag; > + VAR_ERROR_FLAG VarErrFlag; > + > + if (!mEndOfDxe) { > + return; > + } > + > + Flag =3D mCurrentBootVarErrFlag; > + DEBUG ((DEBUG_INFO, "Initialize variable error flag (%02x)\n", Flag)); > + > + Status =3D FindVariable ( > + VAR_ERROR_FLAG_NAME, > + &gEdkiiVarErrorFlagGuid, > + &Variable, > + &mVariableModuleGlobal->VariableGlobal, > + FALSE > + ); > + if (!EFI_ERROR (Status)) { > + VarErrFlag =3D *((VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.Curr= Ptr, > mVariableModuleGlobal->VariableGlobal.AuthFormat)); > + if (VarErrFlag =3D=3D Flag) { > + return; > + } > + } > + > + UpdateVariable ( > + VAR_ERROR_FLAG_NAME, > + &gEdkiiVarErrorFlagGuid, > + &Flag, > + sizeof (Flag), > + VARIABLE_ATTRIBUTE_NV_BS_RT, > + 0, > + 0, > + &Variable, > + NULL > + ); > +} > + > +/** > + Is user variable? > + > + @param[in] Variable Pointer to variable header. > + > + @retval TRUE User variable. > + @retval FALSE System variable. > + > +**/ > +BOOLEAN > +IsUserVariable ( > + IN VARIABLE_HEADER *Variable > + ) > +{ > + VAR_CHECK_VARIABLE_PROPERTY Property; > + > + // > + // Only after End Of Dxe, the variables belong to system variable are = fixed. > + // If PcdMaxUserNvStorageVariableSize is 0, it means user variable sha= re the > same NV storage with system variable, > + // then no need to check if the variable is user variable or not speci= ally. > + // > + if (mEndOfDxe && (mVariableModuleGlobal- > >CommonMaxUserVariableSpace !=3D mVariableModuleGlobal- > >CommonVariableSpace)) { > + if (VarCheckLibVariablePropertyGet ( > + GetVariableNamePtr (Variable, mVariableModuleGlobal- > >VariableGlobal.AuthFormat), > + GetVendorGuidPtr (Variable, mVariableModuleGlobal- > >VariableGlobal.AuthFormat), > + &Property > + ) =3D=3D EFI_NOT_FOUND) > + { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + Calculate common user variable total size. > + > +**/ > +VOID > +CalculateCommonUserVariableTotalSize ( > + VOID > + ) > +{ > + VARIABLE_HEADER *Variable; > + VARIABLE_HEADER *NextVariable; > + UINTN VariableSize; > + VAR_CHECK_VARIABLE_PROPERTY Property; > + > + // > + // Only after End Of Dxe, the variables belong to system variable are = fixed. > + // If PcdMaxUserNvStorageVariableSize is 0, it means user variable sha= re the > same NV storage with system variable, > + // then no need to calculate the common user variable total size speci= ally. > + // > + if (mEndOfDxe && (mVariableModuleGlobal- > >CommonMaxUserVariableSpace !=3D mVariableModuleGlobal- > >CommonVariableSpace)) { > + Variable =3D GetStartPointer (mNvVariableCache); > + while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCa= che), > mVariableModuleGlobal->VariableGlobal.AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlob= al- > >VariableGlobal.AuthFormat); > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != =3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + if (VarCheckLibVariablePropertyGet ( > + GetVariableNamePtr (Variable, mVariableModuleGlobal- > >VariableGlobal.AuthFormat), > + GetVendorGuidPtr (Variable, mVariableModuleGlobal- > >VariableGlobal.AuthFormat), > + &Property > + ) =3D=3D EFI_NOT_FOUND) > + { > + // > + // No property, it is user variable. > + // > + mVariableModuleGlobal->CommonUserVariableTotalSize +=3D Variab= leSize; > + } > + } > + > + Variable =3D NextVariable; > + } > + } > +} > + > +/** > + Initialize variable quota. > + > +**/ > +VOID > +InitializeVariableQuota ( > + VOID > + ) > +{ > + if (!mEndOfDxe) { > + return; > + } > + > + InitializeVarErrorFlag (); > + CalculateCommonUserVariableTotalSize (); > +} > + > +/** > + Finds variable in storage blocks of volatile and non-volatile storage = areas. > + > + This code finds variable in storage blocks of volatile and non-volatil= e storage > areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + If IgnoreRtCheck is TRUE, then we ignore the > EFI_VARIABLE_RUNTIME_ACCESS attribute check > + at runtime when searching existing variable, only VariableName and > VendorGuid are compared. > + Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visib= le > at runtime. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Vendor GUID to be found. > + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure f= or > output, > + including the range searched and t= he target position. > + @param[in] Global Pointer to VARIABLE_GLOBAL structu= re, > including > + base of volatile variable storage = area, base of > + NV variable storage area, and a lo= ck. > + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS > attribute > + check at runtime when searching va= riable. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty st= ring, > while > + VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +FindVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT VARIABLE_POINTER_TRACK *PtrTrack, > + IN VARIABLE_GLOBAL *Global, > + IN BOOLEAN IgnoreRtCheck > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; > + VARIABLE_STORE_TYPE Type; > + > + if ((VariableName[0] !=3D 0) && (VendorGuid =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // 0: Volatile, 1: HOB, 2: Non-Volatile. > + // The index and attributes mapping must be kept in this order as > RuntimeServiceGetNextVariableName > + // make use of this mapping to implement search algorithm. > + // > + VariableStoreHeader[VariableStoreTypeVolatile] =3D > (VARIABLE_STORE_HEADER *)(UINTN)Global->VolatileVariableBase; > + VariableStoreHeader[VariableStoreTypeHob] =3D (VARIABLE_STORE_HEA= DER > *)(UINTN)Global->HobVariableBase; > + VariableStoreHeader[VariableStoreTypeNv] =3D mNvVariableCache; > + > + // > + // Find the variable by walk through HOB, volatile and non-volatile va= riable > store. > + // > + for (Type =3D (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Typ= e++) > { > + if (VariableStoreHeader[Type] =3D=3D NULL) { > + continue; > + } > + > + PtrTrack->StartPtr =3D GetStartPointer (VariableStoreHeader[Type]); > + PtrTrack->EndPtr =3D GetEndPointer (VariableStoreHeader[Type]); > + PtrTrack->Volatile =3D (BOOLEAN)(Type =3D=3D VariableStoreTypeVolati= le); > + > + Status =3D FindVariableEx ( > + VariableName, > + VendorGuid, > + IgnoreRtCheck, > + PtrTrack, > + mVariableModuleGlobal->VariableGlobal.AuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + return Status; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** > + Get index from supported language codes according to language string. > + > + This code is used to get corresponding index in supported language cod= es. It > can handle > + RFC4646 and ISO639 language tags. > + In ISO639 language tags, take 3-characters as a delimitation to find m= atched > string and calculate the index. > + In RFC4646 language tags, take semicolon as a delimitation to find mat= ched > string and calculate the index. > + > + For example: > + SupportedLang =3D "engfraengfra" > + Lang =3D "eng" > + Iso639Language =3D TRUE > + The return value is "0". > + Another example: > + SupportedLang =3D "en;fr;en-US;fr-FR" > + Lang =3D "fr-FR" > + Iso639Language =3D FALSE > + The return value is "3". > + > + @param SupportedLang Platform supported language codes. > + @param Lang Configured language. > + @param Iso639Language A bool value to signify if the han= dler is > operated on ISO639 or RFC4646. > + > + @retval The index of language in the language codes. > + > +**/ > +UINTN > +GetIndexFromSupportedLangCodes ( > + IN CHAR8 *SupportedLang, > + IN CHAR8 *Lang, > + IN BOOLEAN Iso639Language > + ) > +{ > + UINTN Index; > + UINTN CompareLength; > + UINTN LanguageLength; > + > + if (Iso639Language) { > + CompareLength =3D ISO_639_2_ENTRY_SIZE; > + for (Index =3D 0; Index < AsciiStrLen (SupportedLang); Index +=3D Co= mpareLength) > { > + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) =3D= =3D 0) { > + // > + // Successfully find the index of Lang string in SupportedLang s= tring. > + // > + Index =3D Index / CompareLength; > + return Index; > + } > + } > + > + ASSERT (FALSE); > + return 0; > + } else { > + // > + // Compare RFC4646 language code > + // > + Index =3D 0; > + for (LanguageLength =3D 0; Lang[LanguageLength] !=3D '\0'; LanguageL= ength++) > { > + } > + > + for (Index =3D 0; *SupportedLang !=3D '\0'; Index++, SupportedLang += =3D > CompareLength) { > + // > + // Skip ';' characters in SupportedLang > + // > + for ( ; *SupportedLang !=3D '\0' && *SupportedLang =3D=3D ';'; Sup= portedLang++) { > + } > + > + // > + // Determine the length of the next language code in SupportedLang > + // > + for (CompareLength =3D 0; SupportedLang[CompareLength] !=3D '\0' &= & > SupportedLang[CompareLength] !=3D ';'; CompareLength++) { > + } > + > + if ((CompareLength =3D=3D LanguageLength) && > + (AsciiStrnCmp (Lang, SupportedLang, CompareLength) =3D=3D 0)) > + { > + // > + // Successfully find the index of Lang string in SupportedLang s= tring. > + // > + return Index; > + } > + } > + > + ASSERT (FALSE); > + return 0; > + } > +} > + > +/** > + Get language string from supported language codes according to index. > + > + This code is used to get corresponding language strings in supported l= anguage > codes. It can handle > + RFC4646 and ISO639 language tags. > + In ISO639 language tags, take 3-characters as a delimitation. Find lan= guage > string according to the index. > + In RFC4646 language tags, take semicolon as a delimitation. Find langu= age > string according to the index. > + > + For example: > + SupportedLang =3D "engfraengfra" > + Index =3D "1" > + Iso639Language =3D TRUE > + The return value is "fra". > + Another example: > + SupportedLang =3D "en;fr;en-US;fr-FR" > + Index =3D "1" > + Iso639Language =3D FALSE > + The return value is "fr". > + > + @param SupportedLang Platform supported language codes. > + @param Index The index in supported language co= des. > + @param Iso639Language A bool value to signify if the han= dler is > operated on ISO639 or RFC4646. > + > + @retval The language string in the language codes. > + > +**/ > +CHAR8 * > +GetLangFromSupportedLangCodes ( > + IN CHAR8 *SupportedLang, > + IN UINTN Index, > + IN BOOLEAN Iso639Language > + ) > +{ > + UINTN SubIndex; > + UINTN CompareLength; > + CHAR8 *Supported; > + > + SubIndex =3D 0; > + Supported =3D SupportedLang; > + if (Iso639Language) { > + // > + // According to the index of Lang string in SupportedLang string to = get the > language. > + // This code will be invoked in RUNTIME, therefore there is not a me= mory > allocate/free operation. > + // In driver entry, it pre-allocates a runtime attribute memory to > accommodate this string. > + // > + CompareLength =3D ISO_639_2_ENTRY_SIZE; > + mVariableModuleGlobal->Lang[CompareLength] =3D '\0'; > + return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * > CompareLength, CompareLength); > + } else { > + while (TRUE) { > + // > + // Take semicolon as delimitation, sequentially traverse supported= language > codes. > + // > + for (CompareLength =3D 0; *Supported !=3D ';' && *Supported !=3D '= \0'; > CompareLength++) { > + Supported++; > + } > + > + if ((*Supported =3D=3D '\0') && (SubIndex !=3D Index)) { > + // > + // Have completed the traverse, but not find corrsponding string= . > + // This case is not allowed to happen. > + // > + ASSERT (FALSE); > + return NULL; > + } > + > + if (SubIndex =3D=3D Index) { > + // > + // According to the index of Lang string in SupportedLang string= to get the > language. > + // As this code will be invoked in RUNTIME, therefore there is n= ot memory > allocate/free operation. > + // In driver entry, it pre-allocates a runtime attribute memory = to > accommodate this string. > + // > + mVariableModuleGlobal->PlatformLang[CompareLength] =3D '\0'; > + return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - > CompareLength, CompareLength); > + } > + > + SubIndex++; > + > + // > + // Skip ';' characters in Supported > + // > + for ( ; *Supported !=3D '\0' && *Supported =3D=3D ';'; Supported++= ) { > + } > + } > + } > +} > + > +/** > + Returns a pointer to an allocated buffer that contains the best matchi= ng > language > + from a set of supported languages. > + > + This function supports both ISO 639-2 and RFC 4646 language codes, but > language > + code types may not be mixed in a single call to this function. This fu= nction > + supports a variable argument list that allows the caller to pass in a = prioritized > + list of language codes to test against all the language codes in > SupportedLanguages. > + > + If SupportedLanguages is NULL, then ASSERT(). > + > + @param[in] SupportedLanguages A pointer to a Null-terminated ASCII s= tring > that > + contains a set of language codes in th= e format > + specified by Iso639Language. > + @param[in] Iso639Language If not zero, then all language codes a= re > assumed to be > + in ISO 639-2 format. If zero, then al= l language > + codes are assumed to be in RFC 4646 la= nguage format > + @param[in] ... A variable argument list that contains= pointers to > + Null-terminated ASCII strings that con= tain one or more > + language codes in the format specified= by Iso639Language. > + The first language code from each of t= hese language > + code lists is used to determine if it = is an exact or > + close match to any of the language cod= es in > + SupportedLanguages. Close matches onl= y apply to RFC 4646 > + language codes, and the matching algor= ithm from RFC 4647 > + is used to determine if a close match = is present. If > + an exact or close match is found, then= the matching > + language code from SupportedLanguages = is returned. If > + no matches are found, then the next va= riable argument > + parameter is evaluated. The variable = argument list > + is terminated by a NULL. > + > + @retval NULL The best matching language could not be found in > SupportedLanguages. > + @retval NULL There are not enough resources available to return the = best > matching > + language. > + @retval Other A pointer to a Null-terminated ASCII string that is the= best > matching > + language in SupportedLanguages. > + > +**/ > +CHAR8 * > +EFIAPI > +VariableGetBestLanguage ( > + IN CONST CHAR8 *SupportedLanguages, > + IN UINTN Iso639Language, > + ... > + ) > +{ > + VA_LIST Args; > + CHAR8 *Language; > + UINTN CompareLength; > + UINTN LanguageLength; > + CONST CHAR8 *Supported; > + CHAR8 *Buffer; > + > + if (SupportedLanguages =3D=3D NULL) { > + return NULL; > + } > + > + VA_START (Args, Iso639Language); > + while ((Language =3D VA_ARG (Args, CHAR8 *)) !=3D NULL) { > + // > + // Default to ISO 639-2 mode > + // > + CompareLength =3D 3; > + LanguageLength =3D MIN (3, AsciiStrLen (Language)); > + > + // > + // If in RFC 4646 mode, then determine the length of the first RFC 4= 646 > language code in Language > + // > + if (Iso639Language =3D=3D 0) { > + for (LanguageLength =3D 0; Language[LanguageLength] !=3D 0 && > Language[LanguageLength] !=3D ';'; LanguageLength++) { > + } > + } > + > + // > + // Trim back the length of Language used until it is empty > + // > + while (LanguageLength > 0) { > + // > + // Loop through all language codes in SupportedLanguages > + // > + for (Supported =3D SupportedLanguages; *Supported !=3D '\0'; Suppo= rted +=3D > CompareLength) { > + // > + // In RFC 4646 mode, then Loop through all language codes in > SupportedLanguages > + // > + if (Iso639Language =3D=3D 0) { > + // > + // Skip ';' characters in Supported > + // > + for ( ; *Supported !=3D '\0' && *Supported =3D=3D ';'; Support= ed++) { > + } > + > + // > + // Determine the length of the next language code in Supported > + // > + for (CompareLength =3D 0; Supported[CompareLength] !=3D 0 && > Supported[CompareLength] !=3D ';'; CompareLength++) { > + } > + > + // > + // If Language is longer than the Supported, then skip to the = next > language > + // > + if (LanguageLength > CompareLength) { > + continue; > + } > + } > + > + // > + // See if the first LanguageLength characters in Supported match= Language > + // > + if (AsciiStrnCmp (Supported, Language, LanguageLength) =3D=3D 0)= { > + VA_END (Args); > + > + Buffer =3D (Iso639Language !=3D 0) ? mVariableM= oduleGlobal->Lang : > mVariableModuleGlobal->PlatformLang; > + Buffer[CompareLength] =3D '\0'; > + return CopyMem (Buffer, Supported, CompareLength); > + } > + } > + > + if (Iso639Language !=3D 0) { > + // > + // If ISO 639 mode, then each language can only be tested once > + // > + LanguageLength =3D 0; > + } else { > + // > + // If RFC 4646 mode, then trim Language from the right to the ne= xt '-' > character > + // > + for (LanguageLength--; LanguageLength > 0 && > Language[LanguageLength] !=3D '-'; LanguageLength--) { > + } > + } > + } > + } > + > + VA_END (Args); > + > + // > + // No matches were found > + // > + return NULL; > +} > + > +/** > + This function is to check if the remaining variable space is enough to= set > + all Variables from argument list successfully. The purpose of the chec= k > + is to keep the consistency of the Variables to be in variable storage. > + > + Note: Variables are assumed to be in same storage. > + The set sequence of Variables will be same with the sequence of Variab= leEntry > from argument list, > + so follow the argument sequence to check the Variables. > + > + @param[in] Attributes Variable attributes for Variable entries= . > + @param[in] Marker VA_LIST style variable argument list. > + The variable argument list with type > VARIABLE_ENTRY_CONSISTENCY *. > + A NULL terminates the list. The Variable= Size of > + VARIABLE_ENTRY_CONSISTENCY is the variab= le data size as > input. > + It will be changed to variable total siz= e as output. > + > + @retval TRUE Have enough variable space to set the Va= riables > successfully. > + @retval FALSE No enough variable space to set the Vari= ables > successfully. > + > +**/ > +BOOLEAN > +EFIAPI > +CheckRemainingSpaceForConsistencyInternal ( > + IN UINT32 Attributes, > + IN VA_LIST Marker > + ) > +{ > + EFI_STATUS Status; > + VA_LIST Args; > + VARIABLE_ENTRY_CONSISTENCY *VariableEntry; > + UINT64 MaximumVariableStorageSize; > + UINT64 RemainingVariableStorageSize; > + UINT64 MaximumVariableSize; > + UINTN TotalNeededSize; > + UINTN OriginalVarSize; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + VARIABLE_POINTER_TRACK VariablePtrTrack; > + VARIABLE_HEADER *NextVariable; > + UINTN VarNameSize; > + UINTN VarDataSize; > + > + // > + // Non-Volatile related. > + // > + VariableStoreHeader =3D mNvVariableCache; > + > + Status =3D VariableServiceQueryVariableInfoInternal ( > + Attributes, > + &MaximumVariableStorageSize, > + &RemainingVariableStorageSize, > + &MaximumVariableSize > + ); > + ASSERT_EFI_ERROR (Status); > + > + TotalNeededSize =3D 0; > + VA_COPY (Args, Marker); > + VariableEntry =3D VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); > + while (VariableEntry !=3D NULL) { > + // > + // Calculate variable total size. > + // > + VarNameSize =3D StrSize (VariableEntry->Name); > + VarNameSize +=3D GET_PAD_SIZE (VarNameSize); > + VarDataSize =3D VariableEntry->VariableSize; > + VarDataSize +=3D GET_PAD_SIZE (VarDataSize); > + VariableEntry->VariableSize =3D HEADER_ALIGN ( > + GetVariableHeaderSize ( > + mVariableModuleGlobal->VariableGlo= bal.AuthFormat > + ) + VarNameSize + VarDataSize > + ); > + > + TotalNeededSize +=3D VariableEntry->VariableSize; > + VariableEntry =3D VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); > + } > + > + VA_END (Args); > + > + if (RemainingVariableStorageSize >=3D TotalNeededSize) { > + // > + // Already have enough space. > + // > + return TRUE; > + } else if (AtRuntime ()) { > + // > + // At runtime, no reclaim. > + // The original variable space of Variables can't be reused. > + // > + return FALSE; > + } > + > + VA_COPY (Args, Marker); > + VariableEntry =3D VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *); > + while (VariableEntry !=3D NULL) { > + // > + // Check if Variable[Index] has been present and get its size. > + // > + OriginalVarSize =3D 0; > + VariablePtrTrack.StartPtr =3D GetStartPointer (VariableStoreHeader); > + VariablePtrTrack.EndPtr =3D GetEndPointer (VariableStoreHeader); > + Status =3D FindVariableEx ( > + VariableEntry->Name, > + VariableEntry->Guid, > + FALSE, > + &VariablePtrTrack, > + mVariableModuleGlobal->VariableGlobal.= AuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Get size of Variable[Index]. > + // > + NextVariable =3D GetNextVariablePtr (VariablePtrTrack.CurrPtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + OriginalVarSize =3D (UINTN)NextVariable - (UINTN)VariablePtrTrack.= CurrPtr; > + // > + // Add the original size of Variable[Index] to remaining variable = storage size. > + // > + RemainingVariableStorageSize +=3D OriginalVarSize; > + } > + > + if (VariableEntry->VariableSize > RemainingVariableStorageSize) { > + // > + // No enough space for Variable[Index]. > + // > + VA_END (Args); > + return FALSE; > + } > + > + // > + // Sub the (new) size of Variable[Index] from remaining variable sto= rage size. > + // > + RemainingVariableStorageSize -=3D VariableEntry->VariableSize; > + VariableEntry =3D VA_ARG (Args, VARIABLE_ENTRY_CONSI= STENCY *); > + } > + > + VA_END (Args); > + > + return TRUE; > +} > + > +/** > + This function is to check if the remaining variable space is enough to= set > + all Variables from argument list successfully. The purpose of the chec= k > + is to keep the consistency of the Variables to be in variable storage. > + > + Note: Variables are assumed to be in same storage. > + The set sequence of Variables will be same with the sequence of Variab= leEntry > from argument list, > + so follow the argument sequence to check the Variables. > + > + @param[in] Attributes Variable attributes for Variable entries= . > + @param ... The variable argument list with type > VARIABLE_ENTRY_CONSISTENCY *. > + A NULL terminates the list. The Variable= Size of > + VARIABLE_ENTRY_CONSISTENCY is the variab= le data size as > input. > + It will be changed to variable total siz= e as output. > + > + @retval TRUE Have enough variable space to set the Va= riables > successfully. > + @retval FALSE No enough variable space to set the Vari= ables > successfully. > + > +**/ > +BOOLEAN > +EFIAPI > +CheckRemainingSpaceForConsistency ( > + IN UINT32 Attributes, > + ... > + ) > +{ > + VA_LIST Marker; > + BOOLEAN Return; > + > + VA_START (Marker, Attributes); > + > + Return =3D CheckRemainingSpaceForConsistencyInternal (Attributes, Mark= er); > + > + VA_END (Marker); > + > + return Return; > +} > + > +/** > + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and > Lang. > + > + When setting Lang/LangCodes, simultaneously update > PlatformLang/PlatformLangCodes. > + > + According to UEFI spec, PlatformLangCodes/LangCodes are only set once = in > firmware initialization, > + and are read-only. Therefore, in variable driver, only store the origi= nal value > for other use. > + > + @param[in] VariableName Name of variable. > + > + @param[in] Data Variable data. > + > + @param[in] DataSize Size of data. 0 means delete. > + > + @retval EFI_SUCCESS The update operation is successful or ig= nored. > + @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at > runtime. > + @retval EFI_OUT_OF_RESOURCES No enough variable space to do the > update operation. > + @retval Others Other errors happened during the update = operation. > + > +**/ > +EFI_STATUS > +AutoUpdateLangVariable ( > + IN CHAR16 *VariableName, > + IN VOID *Data, > + IN UINTN DataSize > + ) > +{ > + EFI_STATUS Status; > + CHAR8 *BestPlatformLang; > + CHAR8 *BestLang; > + UINTN Index; > + UINT32 Attributes; > + VARIABLE_POINTER_TRACK Variable; > + BOOLEAN SetLanguageCodes; > + VARIABLE_ENTRY_CONSISTENCY VariableEntry[2]; > + > + // > + // Don't do updates for delete operation > + // > + if (DataSize =3D=3D 0) { > + return EFI_SUCCESS; > + } > + > + SetLanguageCodes =3D FALSE; > + > + if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) > =3D=3D 0) { > + // > + // PlatformLangCodes is a volatile variable, so it can not be update= d at > runtime. > + // > + if (AtRuntime ()) { > + return EFI_WRITE_PROTECTED; > + } > + > + SetLanguageCodes =3D TRUE; > + > + // > + // According to UEFI spec, PlatformLangCodes is only set once in fir= mware > initialization, and is read-only > + // Therefore, in variable driver, only store the original value for = other use. > + // > + if (mVariableModuleGlobal->PlatformLangCodes !=3D NULL) { > + FreePool (mVariableModuleGlobal->PlatformLangCodes); > + } > + > + mVariableModuleGlobal->PlatformLangCodes =3D AllocateRuntimeCopyPool > (DataSize, Data); > + ASSERT (mVariableModuleGlobal->PlatformLangCodes !=3D NULL); > + > + // > + // PlatformLang holds a single language from PlatformLangCodes, > + // so the size of PlatformLangCodes is enough for the PlatformLang. > + // > + if (mVariableModuleGlobal->PlatformLang !=3D NULL) { > + FreePool (mVariableModuleGlobal->PlatformLang); > + } > + > + mVariableModuleGlobal->PlatformLang =3D AllocateRuntimePool (DataSiz= e); > + ASSERT (mVariableModuleGlobal->PlatformLang !=3D NULL); > + } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) =3D=3D = 0) { > + // > + // LangCodes is a volatile variable, so it can not be updated at run= time. > + // > + if (AtRuntime ()) { > + return EFI_WRITE_PROTECTED; > + } > + > + SetLanguageCodes =3D TRUE; > + > + // > + // According to UEFI spec, LangCodes is only set once in firmware > initialization, and is read-only > + // Therefore, in variable driver, only store the original value for = other use. > + // > + if (mVariableModuleGlobal->LangCodes !=3D NULL) { > + FreePool (mVariableModuleGlobal->LangCodes); > + } > + > + mVariableModuleGlobal->LangCodes =3D AllocateRuntimeCopyPool (DataSi= ze, > Data); > + ASSERT (mVariableModuleGlobal->LangCodes !=3D NULL); > + } > + > + if ( SetLanguageCodes > + && (mVariableModuleGlobal->PlatformLangCodes !=3D NULL) > + && (mVariableModuleGlobal->LangCodes !=3D NULL)) > + { > + // > + // Update Lang if PlatformLang is already set > + // Update PlatformLang if Lang is already set > + // > + Status =3D FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, > &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGloba= l, > FALSE); > + if (!EFI_ERROR (Status)) { > + // > + // Update Lang > + // > + VariableName =3D EFI_PLATFORM_LANG_VARIABLE_NAME; > + Data =3D GetVariableDataPtr (Variable.CurrPtr, mVariableMo= duleGlobal- > >VariableGlobal.AuthFormat); > + DataSize =3D DataSizeOfVariable (Variable.CurrPtr, mVariableMo= duleGlobal- > >VariableGlobal.AuthFormat); > + } else { > + Status =3D FindVariable (EFI_LANG_VARIABLE_NAME, > &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGloba= l, > FALSE); > + if (!EFI_ERROR (Status)) { > + // > + // Update PlatformLang > + // > + VariableName =3D EFI_LANG_VARIABLE_NAME; > + Data =3D GetVariableDataPtr (Variable.CurrPtr, mVariable= ModuleGlobal- > >VariableGlobal.AuthFormat); > + DataSize =3D DataSizeOfVariable (Variable.CurrPtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + } else { > + // > + // Neither PlatformLang nor Lang is set, directly return > + // > + return EFI_SUCCESS; > + } > + } > + } > + > + Status =3D EFI_SUCCESS; > + > + // > + // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT > attributions. > + // > + Attributes =3D EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; > + > + if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) =3D=3D 0) { > + // > + // Update Lang when PlatformLangCodes/LangCodes were set. > + // > + if ((mVariableModuleGlobal->PlatformLangCodes !=3D NULL) && > (mVariableModuleGlobal->LangCodes !=3D NULL)) { > + // > + // When setting PlatformLang, firstly get most matched language st= ring > from supported language codes. > + // > + BestPlatformLang =3D VariableGetBestLanguage (mVariableModuleGloba= l- > >PlatformLangCodes, FALSE, Data, NULL); > + if (BestPlatformLang !=3D NULL) { > + // > + // Get the corresponding index in language codes. > + // > + Index =3D GetIndexFromSupportedLangCodes (mVariableModuleGlobal- > >PlatformLangCodes, BestPlatformLang, FALSE); > + > + // > + // Get the corresponding ISO639 language tag according to RFC464= 6 > language tag. > + // > + BestLang =3D GetLangFromSupportedLangCodes (mVariableModuleGloba= l- > >LangCodes, Index, TRUE); > + > + // > + // Check the variable space for both Lang and PlatformLang varia= ble. > + // > + VariableEntry[0].VariableSize =3D ISO_639_2_ENTRY_SIZE + 1; > + VariableEntry[0].Guid =3D &gEfiGlobalVariableGuid; > + VariableEntry[0].Name =3D EFI_LANG_VARIABLE_NAME; > + > + VariableEntry[1].VariableSize =3D AsciiStrSize (BestPlatformLang= ); > + VariableEntry[1].Guid =3D &gEfiGlobalVariableGuid; > + VariableEntry[1].Name =3D EFI_PLATFORM_LANG_VARIABLE_NAM= E; > + if (!CheckRemainingSpaceForConsistency > (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], > NULL)) { > + // > + // No enough variable space to set both Lang and PlatformLang > successfully. > + // > + Status =3D EFI_OUT_OF_RESOURCES; > + } else { > + // > + // Successfully convert PlatformLang to Lang, and set the Best= Lang value > into Lang variable simultaneously. > + // > + FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, > &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); > + > + Status =3D UpdateVariable ( > + EFI_LANG_VARIABLE_NAME, > + &gEfiGlobalVariableGuid, > + BestLang, > + ISO_639_2_ENTRY_SIZE + 1, > + Attributes, > + 0, > + 0, > + &Variable, > + NULL > + ); > + } > + > + DEBUG ((DEBUG_INFO, "Variable Driver Auto Update PlatformLang, > PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Statu= s)); > + } > + } > + } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) =3D=3D 0) { > + // > + // Update PlatformLang when PlatformLangCodes/LangCodes were set. > + // > + if ((mVariableModuleGlobal->PlatformLangCodes !=3D NULL) && > (mVariableModuleGlobal->LangCodes !=3D NULL)) { > + // > + // When setting Lang, firstly get most matched language string fro= m > supported language codes. > + // > + BestLang =3D VariableGetBestLanguage (mVariableModuleGlobal->LangC= odes, > TRUE, Data, NULL); > + if (BestLang !=3D NULL) { > + // > + // Get the corresponding index in language codes. > + // > + Index =3D GetIndexFromSupportedLangCodes (mVariableModuleGlobal- > >LangCodes, BestLang, TRUE); > + > + // > + // Get the corresponding RFC4646 language tag according to ISO63= 9 > language tag. > + // > + BestPlatformLang =3D GetLangFromSupportedLangCodes > (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE); > + > + // > + // Check the variable space for both PlatformLang and Lang varia= ble. > + // > + VariableEntry[0].VariableSize =3D AsciiStrSize (BestPlatformLang= ); > + VariableEntry[0].Guid =3D &gEfiGlobalVariableGuid; > + VariableEntry[0].Name =3D EFI_PLATFORM_LANG_VARIABLE_NAM= E; > + > + VariableEntry[1].VariableSize =3D ISO_639_2_ENTRY_SIZE + 1; > + VariableEntry[1].Guid =3D &gEfiGlobalVariableGuid; > + VariableEntry[1].Name =3D EFI_LANG_VARIABLE_NAME; > + if (!CheckRemainingSpaceForConsistency > (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], > NULL)) { > + // > + // No enough variable space to set both PlatformLang and Lang > successfully. > + // > + Status =3D EFI_OUT_OF_RESOURCES; > + } else { > + // > + // Successfully convert Lang to PlatformLang, and set the > BestPlatformLang value into PlatformLang variable simultaneously. > + // > + FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, > &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGloba= l, > FALSE); > + > + Status =3D UpdateVariable ( > + EFI_PLATFORM_LANG_VARIABLE_NAME, > + &gEfiGlobalVariableGuid, > + BestPlatformLang, > + AsciiStrSize (BestPlatformLang), > + Attributes, > + 0, > + 0, > + &Variable, > + NULL > + ); > + } > + > + DEBUG ((DEBUG_INFO, "Variable Driver Auto Update Lang, Lang:%a, > PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status)); > + } > + } > + } > + > + if (SetLanguageCodes) { > + // > + // Continue to set PlatformLangCodes or LangCodes. > + // > + return EFI_SUCCESS; > + } else { > + return Status; > + } > +} > + > +/** > + Check if there's enough free space in storage to write the new variabl= e. > + > + @param[in] NewVariable Pointer to buffer of new variable. > + @param[in] VariableSize Size of new variable. > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Attributes Attributes of the variable. > + @param[in] VolatileFlag Volatile/non-volatile variable indicator= . > + > + @retval EFI_SUCCESS Enough free space on variable storage. > + @retval EFI_BUFFER_TOO_SMALL There's not enough continuous free space= . > + @retval EFI_OUT_OF_RESOURCES There's not enough free space in total. > +**/ > +EFI_STATUS > +CheckVariableStoreSpace ( > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN VariableSize, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN BOOLEAN VolatileFlag > + ) > +{ > + BOOLEAN IsCommonVariable; > + BOOLEAN IsCommonUserVariable; > + UINTN CommonVariableTotalSize; > + UINTN CommonUserVariableTotalSize; > + UINTN HwErrVariableTotalSize; > + VARIABLE_STORE_HEADER *VarStore; > + > + if ((NewVariable =3D=3D NULL) || (VariableSize =3D=3D 0)) { > + return EFI_SUCCESS; > + } > + > + if (VolatileFlag) { > + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) > + mVariableModuleGlobal->VariableGlobal.VolatileVariableBas= e; > + if ((UINT32)(VariableSize + mVariableModuleGlobal- > >VolatileLastVariableOffset) > + > VarStore->Size) > + { > + return EFI_BUFFER_TOO_SMALL; > + } > + } else { > + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0) { > + IsCommonVariable =3D TRUE; > + IsCommonUserVariable =3D IsUserVariable (NewVariable); > + } else { > + IsCommonVariable =3D FALSE; > + IsCommonUserVariable =3D FALSE; > + } > + > + CommonVariableTotalSize =3D mVariableModuleGlobal- > >CommonVariableTotalSize + VariableSize; > + CommonUserVariableTotalSize =3D mVariableModuleGlobal- > >CommonUserVariableTotalSize + VariableSize; > + HwErrVariableTotalSize =3D mVariableModuleGlobal- > >HwErrVariableTotalSize + VariableSize; > + > + if ( (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) && > + (HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize))) > + || (IsCommonVariable && (CommonVariableTotalSize > > mVariableModuleGlobal->CommonVariableSpace)) > + || (IsCommonVariable && > + AtRuntime () && > + (CommonVariableTotalSize > mVariableModuleGlobal- > >CommonRuntimeVariableSpace)) > + || (IsCommonUserVariable && > + (CommonUserVariableTotalSize > mVariableModuleGlobal- > >CommonMaxUserVariableSpace))) > + { > + if (AtRuntime ()) { > + if (IsCommonUserVariable && > + ((VariableSize + mVariableModuleGlobal- > >CommonUserVariableTotalSize) > + > mVariableModuleGlobal->CommonMaxUserVariableSpace)) > + { > + RecordVarErrorFlag ( > + VAR_ERROR_FLAG_USER_ERROR, > + VariableName, > + VendorGuid, > + Attributes, > + VariableSize > + ); > + } > + > + if (IsCommonVariable && > + ((VariableSize + mVariableModuleGlobal->CommonVariableTotalS= ize) > + > mVariableModuleGlobal->CommonRuntimeVariableSpace)) > + { > + RecordVarErrorFlag ( > + VAR_ERROR_FLAG_SYSTEM_ERROR, > + VariableName, > + VendorGuid, > + Attributes, > + VariableSize > + ); > + } > + > + return EFI_OUT_OF_RESOURCES; > + } > + > + return EFI_BUFFER_TOO_SMALL; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Fill specific data of auth-variable in buffer. > + > + @param[in,out] NewVariable Pointer to buffer of new variable. > + @param[in] OldVariable Pointer to buffer of old copy of th= e variable. > + @param[in] Attributes Attributes of the variable. > + @param[in] KeyIndex Index of associated public key. > + @param[in] MonotonicCount Value of associated monotonic count= . > + @param[in] TimeStamp Value of associated TimeStamp. > + > +**/ > +VOID > +SetVariableAuthData ( > + IN OUT AUTHENTICATED_VARIABLE_HEADER *NewVariable, > + IN AUTHENTICATED_VARIABLE_HEADER *OldVariable, > + IN UINT32 Attributes, > + IN UINT32 KeyIndex, > + IN UINT64 MonotonicCount, > + IN EFI_TIME *TimeStamp > + ) > +{ > + NewVariable->PubKeyIndex =3D KeyIndex; > + NewVariable->MonotonicCount =3D MonotonicCount; > + > + if ((TimeStamp !=3D NULL) && > + ((Attributes & > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) !=3D 0)) > + { > + // > + // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, = only > + // when the new TimeStamp value is later than the current timestamp > associated > + // with the variable, we need associate the new timestamp with the u= pdated > value. > + // > + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) !=3D 0) && > + (OldVariable !=3D NULL) && > + !VariableCompareTimeStampInternal (&OldVariable->TimeStamp, > TimeStamp)) > + { > + TimeStamp =3D &OldVariable->TimeStamp; > + } > + > + CopyMem (&NewVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME)); > + } else { > + ZeroMem (&NewVariable->TimeStamp, sizeof (EFI_TIME)); > + } > +} > + > +/** > + Fill the variable data buffer according to variable format on storage. > + > + @param[in,out] NewVariable Pointer to buffer of new variable. > + @param[in] OldVariable Pointer to buffer of old copy of th= e variable. > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Data Variable data. > + @param[in] DataSize Size of data. 0 means delete. > + @param[in] Attributes Attributes of the variable. > + @param[in] KeyIndex Index of associated public key. > + @param[in] MonotonicCount Value of associated monotonic count= . > + @param[in] TimeStamp Value of associated TimeStamp. > + > + @retval Size of the new variable. > + > +**/ > +UINTN > +SetVariableData ( > + IN OUT VARIABLE_HEADER *NewVariable, > + IN VARIABLE_HEADER *OldVariable, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VOID *Data, > + IN UINTN DataSize, > + IN UINT32 Attributes, > + IN UINT32 KeyIndex, > + IN UINT64 MonotonicCount, > + IN EFI_TIME *TimeStamp > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN AuthFormat; > + UINT8 *DataPtr; > + UINTN NameSize; > + UINTN OldDataSize; > + > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + if (AuthFormat) { > + SetVariableAuthData ( > + (AUTHENTICATED_VARIABLE_HEADER *)NewVariable, > + (AUTHENTICATED_VARIABLE_HEADER *)OldVariable, > + Attributes, > + KeyIndex, > + MonotonicCount, > + TimeStamp > + ); > + } > + > + NewVariable->StartId =3D VARIABLE_DATA; > + NewVariable->State =3D VAR_ADDED; > + NewVariable->Reserved =3D 0; > + NewVariable->Attributes =3D Attributes & (~EFI_VARIABLE_APPEND_WRITE); > + > + CopyMem ( > + GetVendorGuidPtr (NewVariable, AuthFormat), > + VendorGuid, > + sizeof (EFI_GUID) > + ); > + > + NameSize =3D StrSize (VariableName); > + SetNameSizeOfVariable (NewVariable, NameSize, AuthFormat); > + CopyMem ( > + (UINT8 *)GetVariableNamePtr (NewVariable, AuthFormat), > + VariableName, > + NameSize > + ); > + > + // > + // Set data size first otherwise we can't get correct data pointer in = the > + // buffer of new variable. > + // > + SetDataSizeOfVariable (NewVariable, DataSize, AuthFormat); > + DataPtr =3D GetVariableDataPtr (NewVariable, AuthFormat); > + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) !=3D 0) && > + (OldVariable !=3D NULL) && > + ((OldVariable->State =3D=3D VAR_ADDED) || > + (OldVariable->State =3D=3D (VAR_ADDED & VAR_IN_DELETED_TRANSITION= )))) > + { > + // > + // Get old data, which might be encrypted. > + // > + OldDataSize =3D mVariableModuleGlobal->ScratchBufferSize > + - ((UINTN)DataPtr - (UINTN)NewVariable); > + Status =3D ProtectedVariableLibGetByBuffer ( > + OldVariable, > + DataPtr, > + (UINT32 *)&OldDataSize, > + AuthFormat > + ); > + if (Status =3D=3D EFI_UNSUPPORTED) { > + OldDataSize =3D DataSizeOfVariable (OldVariable, AuthFormat); > + CopyMem (DataPtr, GetVariableDataPtr (OldVariable, AuthFormat), > OldDataSize); > + } else if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return 0; > + } > + > + DataPtr +=3D OldDataSize; > + // > + // Update data size. > + // > + SetDataSizeOfVariable (NewVariable, DataSize + OldDataSize, AuthForm= at); > + } > + > + CopyMem (DataPtr, Data, DataSize); > + > + // > + // The actual size of the variable stored in storage should include pa= dding. > + // > + return ((UINTN)GetNextVariablePtr (NewVariable, AuthFormat) - > (UINTN)NewVariable); > +} > + > +/** > + Update state of given variable as well as its cached copy. > + > + @param[in,out] Variable Pointer to the buffer of the variable. > + @param[in,out] CacheVariable Cache copy of the variable. > + @param[in] NewState New state value. > + @param[in] Volatile Volatile/non-volatile variable indicat= or. > + > + @retval EFI_SUCCESS Variable state was updated successfully. > + @retval Others Failed to update the variable state. > + > +**/ > +EFI_STATUS > +UpdateVariableState ( > + IN OUT VARIABLE_HEADER *Variable, > + IN OUT VARIABLE_HEADER *CacheVariable, > + IN UINT8 NewState, > + IN BOOLEAN Volatile > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D UpdateVariableStore ( > + &mVariableModuleGlobal->VariableGlobal, > + Volatile, > + FALSE, > + mVariableModuleGlobal->FvbInstance, > + (UINTN)&Variable->State, > + sizeof (NewState), > + &NewState > + ); > + if (!EFI_ERROR (Status) && (CacheVariable !=3D NULL)) { > + CacheVariable->State =3D NewState; > + } > + > + return Status; > +} > + > +/** > + Flush variable data to variable storage. > + > + @param[in] VarStoreBase Base address of variable storage. > + @param[in,out] Offset Offset to write the variable from. > + Offset from where next variable can be= written. > + @param[in,out] NewVariable Pointer to the buffer of new variable. > + @param[in] VariableSize Size of new variable. > + @param[in] Volatile Volatile/non-volatile variable indicat= or. > + @param[in] AuthFormat Auth-variable indicator. > + > + @retval EFI_SUCCESS Variable(s) were written successfully. > + @retval Others Failed to write the variable data. > + > +**/ > +EFI_STATUS > +WriteVariable ( > + IN EFI_PHYSICAL_ADDRESS VarStoreBase, > + IN OUT UINTN *Offset, > + IN OUT VARIABLE_HEADER **NewVariable, > + IN UINT32 VariableSize, > + IN BOOLEAN Volatile, > + IN BOOLEAN AuthFormat > + ) > +{ > + EFI_STATUS Status; > + > + struct { > + UINTN Offset; > + UINT8 *Buffer; > + UINT32 Size; > + UINT8 State; > + } WriteSteps[4]; > + UINTN Index; > + UINTN Steps; > + VARIABLE_HEADER *Variable; > + > + Variable =3D *NewVariable; > + if (Volatile) { > + // > + // For non-volatile variable, one step only : > + // > + WriteSteps[0].Offset =3D *Offset; > + WriteSteps[0].Buffer =3D (UINT8 *)Variable; > + WriteSteps[0].Size =3D VariableSize; > + > + Steps =3D 1; > + } else { > + // > + // Four steps for non-volatile variable: > + // > + // 1. Write variable header > + // 2. Set variable state to header valid > + // 3. Write variable name and data > + // 4. Set variable state to valid > + // > + Variable->State =3D 0xff; > + WriteSteps[0].Offset =3D *Offset; > + WriteSteps[0].Buffer =3D (UINT8 *)Variable; > + WriteSteps[0].Size =3D (UINT32)GetVariableHeaderSize (AuthFormat); > + > + WriteSteps[1].State =3D VAR_HEADER_VALID_ONLY; > + WriteSteps[1].Offset =3D *Offset + OFFSET_OF (VARIABLE_HEADER, State= ); > + WriteSteps[1].Buffer =3D &WriteSteps[1].State; > + WriteSteps[1].Size =3D sizeof (Variable->State); > + > + WriteSteps[2].Offset =3D *Offset + GetVariableHeaderSize (AuthFormat= ); > + WriteSteps[2].Buffer =3D (UINT8 *)Variable + GetVariableHeaderSize > (AuthFormat); > + WriteSteps[2].Size =3D VariableSize - (UINT32)GetVariableHeaderSiz= e > (AuthFormat); > + > + WriteSteps[3].State =3D VAR_ADDED; > + WriteSteps[3].Offset =3D *Offset + OFFSET_OF (VARIABLE_HEADER, State= ); > + WriteSteps[3].Buffer =3D &WriteSteps[3].State; > + WriteSteps[3].Size =3D sizeof (Variable->State); > + > + Steps =3D ARRAY_SIZE (WriteSteps); > + } > + > + for (Index =3D 0; Index < Steps; ++Index) { > + Status =3D UpdateVariableStore ( > + &mVariableModuleGlobal->VariableGlobal, > + Volatile, > + TRUE, > + mVariableModuleGlobal->FvbInstance, > + WriteSteps[Index].Offset, > + WriteSteps[Index].Size, > + WriteSteps[Index].Buffer > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } > + > + Variable->State =3D VAR_ADDED; > + if (!Volatile) { > + CopyMem ((UINT8 *)mNvVariableCache + *Offset, Variable, VariableSize= ); > + } > + > + *NewVariable =3D (VARIABLE_HEADER *)((UINTN)VarStoreBase + *Offset); > + *Offset +=3D HEADER_ALIGN (VariableSize); > + > + return EFI_SUCCESS; > +} > + > +/** > + Rebase the given variable pointer(s) to the equivalent one in given va= riable > + storage via VarStore. > + > + @param[in] InVarTrackPtr Pointer to current variable in cache= . > + @param[out] OutVarTrackPtr Pointer to rebased variable against = VarStore. > + @param[in] VarStore Start of variable storage to rebase = against. > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] ByOffset If TRUE, don't do variable search in= VarStore. > + > + @retval EFI_SUCCESS Variable(s) were deleted successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameters passed. > + @retval EFI_NOT_FOUND Given variable (VariableName & VendorGui= d) > was > + not found in VarStore, if ByOffset is FA= LSE. > + > +**/ > +EFI_STATUS > +RebaseVariablePtr ( > + IN VARIABLE_POINTER_TRACK *InVarTrackPtr, > + OUT VARIABLE_POINTER_TRACK *OutVarTrackPtr, > + IN VARIABLE_STORE_HEADER *VarStore, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN BOOLEAN ByOffset > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN AuthFormat; > + VARIABLE_HEADER *NewStart; > + > + if ((InVarTrackPtr =3D=3D NULL) || (OutVarTrackPtr =3D=3D NULL) || (Va= rStore =3D=3D > NULL)) { > + ASSERT (InVarTrackPtr !=3D NULL); > + ASSERT (OutVarTrackPtr !=3D NULL); > + ASSERT (VarStore !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + if ( (InVarTrackPtr->CurrPtr =3D=3D NULL) > + || (InVarTrackPtr->StartPtr =3D=3D GetStartPointer (VarStore))) > + { > + CopyMem (OutVarTrackPtr, InVarTrackPtr, sizeof > (VARIABLE_POINTER_TRACK)); > + return EFI_SUCCESS; > + } > + > + NewStart =3D GetStartPointer (VarStore); > + if (ByOffset) { > + OutVarTrackPtr->CurrPtr =3D (VARIABLE_HEADER *) > + ((UINTN)NewStart + ((UINTN)InVarTrackPtr->= CurrPtr - > + (UINTN)InVarTrackPtr->= StartPtr)); > + > + if (InVarTrackPtr->InDeletedTransitionPtr !=3D NULL) { > + OutVarTrackPtr->InDeletedTransitionPtr =3D > + (VARIABLE_HEADER *)((UINTN)NewStart + > + ((UINTN)InVarTrackPtr->InDeletedTransitionPt= r - > + (UINTN)InVarTrackPtr->StartPtr)); > + } else { > + OutVarTrackPtr->InDeletedTransitionPtr =3D NULL; > + } > + > + OutVarTrackPtr->StartPtr =3D NewStart; > + OutVarTrackPtr->EndPtr =3D GetEndPointer (VarStore); > + } else { > + OutVarTrackPtr->StartPtr =3D NewStart; > + OutVarTrackPtr->EndPtr =3D GetEndPointer (VarStore); > + > + Status =3D FindVariableEx (VariableName, VendorGuid, FALSE, OutVarTr= ackPtr, > AuthFormat); > + if ((OutVarTrackPtr->CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { > + return EFI_NOT_FOUND; > + } > + } > + > + if ( (VarStore =3D=3D mNvVariableCache) > + || ((UINTN)VarStore =3D=3D (UINTN)mVariableModuleGlobal- > >VariableGlobal.NonVolatileVariableBase)) > + { > + OutVarTrackPtr->Volatile =3D FALSE; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Check if the given variable is from HOB. > + > + @param[in] CacheVariable Pointer to current variable in cache. > + > + @retval TRUE The variable is from HOB. > + @retval FALSE The variable is NOT from HOB. > + > +**/ > +BOOLEAN > +IsHobVariable ( > + IN VARIABLE_POINTER_TRACK *CacheVariable > + ) > +{ > + VARIABLE_STORE_HEADER *HobVarStore; > + > + HobVarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) > + mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + return (CacheVariable->CurrPtr !=3D NULL && > + HobVarStore !=3D NULL && > + CacheVariable->StartPtr =3D=3D GetStartPointer (HobVarStore)); > +} > + > +/** > + Get temporary buffer for a new variable data. > + > + @retval Pointer to the buffer address. > + > +**/ > +VARIABLE_HEADER * > +GetNewVariableBuffer ( > + VOID > + ) > +{ > + VARIABLE_HEADER *NewVariable; > + VARIABLE_STORE_HEADER *VarStore; > + > + // > + // Tricky part: Use scratch data area at the end of volatile variable = store > + // as a temporary storage. > + // > + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) > + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + NewVariable =3D GetEndPointer (VarStore); > + > + SetMem (NewVariable, mVariableModuleGlobal->ScratchBufferSize, 0xff); > + > + return NewVariable; > +} > + > +/** > + Delete old copies of variable completely. > + > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Variable Pointer to current variable on stor= age. > + @param[in,out] CacheVariable Pointer to current variable in cach= e. > + @param[in] VolatileFlag Auth-variable indicator. > + > + @retval EFI_SUCCESS Variable(s) were deleted successfully. > + @retval Others Failed to update variable state. > + > +**/ > +EFI_STATUS > +DeleteVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VARIABLE_POINTER_TRACK *Variable, > + IN OUT VARIABLE_POINTER_TRACK *CacheVariable, > + IN BOOLEAN VolatileFlag > + ) > +{ > + EFI_STATUS Status; > + > + if (Variable->InDeletedTransitionPtr !=3D NULL) { > + ASSERT (CacheVariable->InDeletedTransitionPtr !=3D NULL); > + // > + // Both ADDED and IN_DELETED_TRANSITION variable are present, > + // set IN_DELETED_TRANSITION one to DELETED state first. > + // > + Status =3D UpdateVariableState ( > + Variable->InDeletedTransitionPtr, > + CacheVariable->InDeletedTransitionPtr, > + CacheVariable->InDeletedTransitionPtr->State & VAR_DELETE= D, > + VolatileFlag > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } > + > + ASSERT (CacheVariable->CurrPtr !=3D NULL); > + Status =3D UpdateVariableState ( > + Variable->CurrPtr, > + CacheVariable->CurrPtr, > + CacheVariable->CurrPtr->State & VAR_DELETED, > + VolatileFlag > + ); > + > + if (!EFI_ERROR (Status)) { > + UpdateVariableInfo ( > + VariableName, > + VendorGuid, > + Variable->Volatile, > + FALSE, > + FALSE, > + TRUE, > + FALSE, > + &gVariableInfo > + ); > + if (!Variable->Volatile) { > + FlushHobVariableToFlash (VariableName, VendorGuid); > + } > + } > + > + return Status; > +} > + > +/** > + Check if it's the right time to update a variable. > + > + @param[in] Attributes Attributes of a variable. > + > + @retval TRUE It's ready for variable update. > + @retval FALSE It's NOT ready for variable update. > + > +**/ > +BOOLEAN > +ReadyForUpdate ( > + IN UINT32 Attributes > + ) > +{ > + if ((mVariableModuleGlobal->FvbInstance =3D=3D NULL) && > + !mVariableModuleGlobal->VariableGlobal.EmuNvMode) > + { > + // > + // The FVB protocol is not ready, so the > EFI_VARIABLE_WRITE_ARCH_PROTOCOL > + // is not installed. > + // > + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { > + // > + // Trying to update NV variable prior to the installation of > + // EFI_VARIABLE_WRITE_ARCH_PROTOCOL > + // > + DEBUG (( > + DEBUG_ERROR, > + "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL > ready - %r\n", > + EFI_NOT_AVAILABLE_YET > + )); > + return FALSE; > + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { > + // > + // Trying to update volatile authenticated variable prior to the > + // installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL. The > authenticated > + // variable perhaps is not initialized, just return here. > + // > + DEBUG (( > + DEBUG_ERROR, > + "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL > ready - %r\n", > + EFI_NOT_AVAILABLE_YET > + )); > + return FALSE; > + } > + } > + > + return TRUE; > +} > + > +/** > + Check parameters associated with the variable to update. > + > + @param[in] Variable Pointer to current variable on storage. > + @param[in] CacheVariable Pointer to current variable in cache. > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Data Variable data. > + @param[in] DataSize Size of data. 0 means delete. > + @param[in] Attributes Attributes of the variable. > + @param[in] KeyIndex Index of associated public key. > + @param[in] MonotonicCount Value of associated monotonic count. > + @param[in] TimeStamp Value of associated TimeStamp. > + > + @retval EFI_SUCCESS The variable is ok to be updated. > + @retval EFI_ALREADY_STARTED No need to update the variable. > + @retval EFI_WRITE_PROTECTED The variable cannot be updated. > + @retval EFI_INVALID_PARAMETER The variable attributes are not valid. > + @retval EFI_NOT_FOUND Trying to delete non-existing variable. > + > +**/ > +EFI_STATUS > +ValidateVariableParameters ( > + IN VARIABLE_POINTER_TRACK *Variable, > + IN VARIABLE_POINTER_TRACK *CacheVariable, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VOID *Data, > + IN UINTN DataSize, > + IN UINT32 Attributes, > + IN UINT32 KeyIndex, > + IN UINT64 MonotonicCount, > + IN EFI_TIME *TimeStamp > + ) > +{ > + BOOLEAN AuthFlag; > + > + AuthFlag =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + if ((DataSize =3D=3D 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != =3D 0)) { > + return EFI_ALREADY_STARTED; > + } > + > + if (Variable->CurrPtr !=3D NULL) { > + // > + // Update/Delete existing variable. > + // > + if (AtRuntime ()) { > + // > + // If AtRuntime and the variable is Volatile and Runtime Access, > + // the volatile is ReadOnly, and SetVariable should be aborted and > + // return EFI_WRITE_PROTECTED. > + // > + if (Variable->Volatile) { > + return EFI_WRITE_PROTECTED; > + } > + > + // > + // Only variable that have NV attributes can be updated/deleted in= Runtime. > + // > + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATIL= E) > =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Only variable that have RT attributes can be updated/deleted in= Runtime. > + // > + if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACC= ESS) > =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + } > + > + // > + // Variable content unchanged and no need to update timestamp, just = return. > + // > + if ( ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) > + && (TimeStamp =3D=3D NULL) > + && (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFlag) =3D=3D = DataSize) > + && (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, > AuthFlag), DataSize) =3D=3D 0)) > + { > + UpdateVariableInfo ( > + VariableName, > + VendorGuid, > + Variable->Volatile, > + FALSE, > + TRUE, > + FALSE, > + FALSE, > + &gVariableInfo > + ); > + return EFI_ALREADY_STARTED; > + } > + } else { > + // > + // Create a new variable. > + // > + > + // > + // Make sure we are trying to create a new variable. You cannot dele= te a > new > + // variable. > + // > + if ((DataSize =3D=3D 0) || > + ((Attributes & > (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS)) =3D=3D > 0)) > + { > + return EFI_NOT_FOUND; > + } > + > + // > + // Only variable have NV|RT attribute can be created in Runtime. > + // > + if ( AtRuntime () > + && ( ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) =3D=3D 0) > + || ((Attributes & EFI_VARIABLE_NON_VOLATILE) =3D=3D 0))) > + { > + return EFI_INVALID_PARAMETER; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Update the variable region with Variable information. If > EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set, > + index of associated public key is needed. > + > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] Data Variable data. > + @param[in] DataSize Size of data. 0 means delete. > + @param[in] Attributes Attributes of the variable. > + @param[in] KeyIndex Index of associated public key. > + @param[in] MonotonicCount Value of associated monotonic count= . > + @param[in,out] CacheVariable The variable information which is u= sed > + to keep track of variable usage. > + @param[in] TimeStamp Value of associated TimeStamp. > + > + @retval EFI_SUCCESS The update operation is success. > + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write o= ther > data into this region. > + > +**/ > +EFI_STATUS > +UpdateVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VOID *Data, > + IN UINTN DataSize, > + IN UINT32 Attributes OPTIONAL, > + IN UINT32 KeyIndex OPTIONAL, > + IN UINT64 MonotonicCount OPTIONAL, > + IN OUT VARIABLE_POINTER_TRACK *CacheVariable, > + IN EFI_TIME *TimeStamp OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_GLOBAL *VarGlobal; > + VARIABLE_HEADER *NewVariable; > + VARIABLE_HEADER *NextVariable; > + VARIABLE_HEADER *UpdatingVariable; > + UINTN VarSize; > + UINTN UpdateSize; > + UINTN Offset; > + VARIABLE_POINTER_TRACK *Variable; > + VARIABLE_POINTER_TRACK NvVariable; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + VARIABLE_RUNTIME_CACHE *VolatileCacheInstance; > + BOOLEAN IsCommonVariable; > + BOOLEAN IsCommonUserVariable; > + BOOLEAN DeleteFlag; > + BOOLEAN VolatileFlag; > + BOOLEAN HobVarOnlyFlag; > + EFI_PHYSICAL_ADDRESS VarStoreBase; > + UINTN *LastVariableOffset; > + > + if (!ReadyForUpdate (Attributes)) { > + return EFI_NOT_AVAILABLE_YET; > + } > + > + VarGlobal =3D &mVariableModuleGlobal->VariableGlobal; > + > + if ( (((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D=3D 0) && (DataSiz= e =3D=3D 0)) > + || (Attributes =3D=3D 0) > + || (AtRuntime () && ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS > + |EFI_VARIABLE_BOOTSERVICE_ACCES= S)) =3D=3D 0))) > + { > + DeleteFlag =3D TRUE; > + } else { > + DeleteFlag =3D FALSE; > + } > + > + if ( ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) > + || ((CacheVariable->CurrPtr !=3D NULL) && > + ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATIL= E) !=3D > 0))) > + { > + VolatileFlag =3D FALSE; > + } else { > + VolatileFlag =3D TRUE; > + } > + > + // > + // Check if CacheVariable points to the variable in variable HOB. > + // If yes, let CacheVariable points to the variable in NV variable cac= he. > + // > + HobVarOnlyFlag =3D FALSE; > + if (IsHobVariable (CacheVariable)) { > + Status =3D RebaseVariablePtr ( > + CacheVariable, > + CacheVariable, > + mNvVariableCache, > + VariableName, > + VendorGuid, > + FALSE > + ); > + if ((CacheVariable->CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { > + // > + // There is no matched variable in NV variable cache. > + // > + if (DeleteFlag) { > + // > + // Leave the deletion to FlushHobVariableToFlash() before return= . > + // > + HobVarOnlyFlag =3D TRUE; > + Status =3D EFI_SUCCESS; > + goto Done; > + } > + } > + } > + > + // > + // Determine the physical position of variable store to update, due to= cache > + // mechanims of variable service. > + // > + if ((CacheVariable->CurrPtr =3D=3D NULL) || CacheVariable->Volatile) { > + // > + // - Add new variable (volatile or non-volatile); Or > + // - Update/delete volatile variable in place. > + // > + Variable =3D CacheVariable; > + } else { > + // > + // - Update/Delete existing NV variable. > + // CacheVariable points to the variable in the memory copy of Fla= sh area. > + // Now let Variable points to the same variable in Flash area. > + // > + VariableStoreHeader =3D (VARIABLE_STORE_HEADER *)(UINTN) > + VarGlobal->NonVolatileVariableBase; > + Variable =3D &NvVariable; > + Status =3D RebaseVariablePtr ( > + CacheVariable, > + Variable, > + VariableStoreHeader, > + VariableName, > + VendorGuid, > + TRUE > + ); > + ASSERT_EFI_ERROR (Status); > + } > + > + // > + // Validate variable parameters. > + // > + Status =3D ValidateVariableParameters ( > + Variable, > + CacheVariable, > + VariableName, > + VendorGuid, > + Data, > + DataSize, > + Attributes, > + KeyIndex, > + MonotonicCount, > + TimeStamp > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Add or update a variable. Allocate a buffer to hold it temporarily. > + // > + NewVariable =3D GetNewVariableBuffer (); > + > + // > + // Fill-up variable data first, if necessary. > + // > + IsCommonVariable =3D FALSE; > + IsCommonUserVariable =3D FALSE; > + if (DeleteFlag) { > + // > + // No need to fill up variable buffer when deleting a variable. But = the > + // buffer is still needed if variable protection is employed. > + // > + VarSize =3D 0; > + } else { > + VarSize =3D SetVariableData ( > + NewVariable, > + CacheVariable->CurrPtr, > + VariableName, > + VendorGuid, > + Data, > + DataSize, > + Attributes, > + KeyIndex, > + MonotonicCount, > + TimeStamp > + ); > + > + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0) { > + IsCommonVariable =3D TRUE; > + IsCommonUserVariable =3D IsUserVariable (NewVariable); > + } > + } > + > + // > + // We might need to do protection for non-volatile variable before flu= shing > + // the data to storage. A null version (meaning no protection) of foll= owing > + // APIs should simply return EFI_SUCCESS or EFI_UNSUPPORTED without an= y > + // changes to original data. > + // > + if (!VolatileFlag) { > + Status =3D ProtectedVariableLibUpdate ( > + Variable->CurrPtr, > + Variable->InDeletedTransitionPtr, > + NewVariable, > + &VarSize > + ); > + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { > + return Status; > + } > + > + Status =3D EFI_SUCCESS; > + } > + > + // > + // Mark the old variable as in delete transition first. There's no suc= h need > + // for deleting a variable, even if variable protection is employed. > + // > + if ( !DeleteFlag > + && (CacheVariable->CurrPtr !=3D NULL) > + && ( (CacheVariable->CurrPtr->State =3D=3D VAR_ADDED) > + || (CacheVariable->CurrPtr->State =3D=3D (VAR_ADDED & > VAR_IN_DELETED_TRANSITION)))) > + { > + Status =3D UpdateVariableState ( > + Variable->CurrPtr, > + CacheVariable->CurrPtr, > + CacheVariable->CurrPtr->State & VAR_IN_DELETED_TRANSITION= , > + Variable->Volatile > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + } > + > + // > + // Have enough space to store the variable? > + // > + Status =3D CheckVariableStoreSpace ( > + NewVariable, > + VarSize, > + VariableName, > + VendorGuid, > + Attributes, > + VolatileFlag > + ); > + if (Status =3D=3D EFI_OUT_OF_RESOURCES) { > + // > + // Not a chance. > + // > + goto Done; > + } > + > + // > + // Maybe not... > + // > + VarStoreBase =3D (VolatileFlag) ? VarGlobal->VolatileVariableBase > + : VarGlobal->NonVolatileVariableBase; > + LastVariableOffset =3D (VolatileFlag) > + ? &mVariableModuleGlobal->VolatileLastVariableOf= fset > + : &mVariableModuleGlobal->NonVolatileLastVariabl= eOffset; > + if (!EFI_ERROR (Status)) { > + // > + // There's enough free space at the tail of variable storage. > + // > + > + // > + // If non-volatile variable is protected, a separate variable > (MetaDataHmacVar) > + // is always updated along with current updating variable. The buffe= r pointed > + // by NewVariable must have two variables. They should be written at= this > + // time orderly. > + // > + NextVariable =3D NewVariable; > + UpdatingVariable =3D NULL; > + UpdateSize =3D 0; > + while ( !EFI_ERROR (Status) > + && ((UINTN)NextVariable - (UINTN)NewVariable) < VarSize) > + { > + UpdatingVariable =3D NextVariable; > + NextVariable =3D GetNextVariablePtr (UpdatingVariable, VarGlob= al- > >AuthFormat); > + UpdateSize =3D (UINTN)NextVariable - (UINTN)UpdatingVariable= ; > + > + Status =3D WriteVariable ( > + VarStoreBase, > + LastVariableOffset, > + &UpdatingVariable, > + (UINT32)UpdateSize, > + VolatileFlag, > + VarGlobal->AuthFormat > + ); > + } > + > + // > + // UpdatingVariable must point to the last written variable. Restore= it to > + // the first one so that we can calculate the offset in variable sto= rage. > + // > + UpdatingVariable =3D (VARIABLE_HEADER *)((UINTN)UpdatingVariable + > UpdateSize > + - VarSize); > + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) { > + mVariableModuleGlobal->HwErrVariableTotalSize +=3D VarSize; > + } else { > + mVariableModuleGlobal->CommonVariableTotalSize +=3D VarSize; > + if (IsCommonUserVariable) { > + mVariableModuleGlobal->CommonUserVariableTotalSize +=3D VarSize; > + } > + } > + > + // > + // Mark the old variable(s) as deleted. > + // > + if (!EFI_ERROR (Status) && (Variable->CurrPtr !=3D NULL)) { > + Status =3D DeleteVariable ( > + VariableName, > + VendorGuid, > + Variable, > + CacheVariable, > + VolatileFlag > + ); > + } > + } else { > + // > + // There's not enough space at the tail of variable storage but ther= e's > + // enough free space holes in the whole storage. Perform garbage col= lection > + // & reclaim operation, and integrate the new variable at the same t= ime. > + // > + Status =3D Reclaim ( > + VarStoreBase, > + LastVariableOffset, > + VolatileFlag, > + Variable, > + NewVariable, > + VarSize > + ); > + > + if (Variable->CurrPtr !=3D NULL) { > + UpdatingVariable =3D Variable->CurrPtr; > + } else { > + UpdatingVariable =3D (VARIABLE_HEADER *)(((UINTN)VarStoreBase + > *LastVariableOffset) - VarSize); > + } > + > + if (EFI_ERROR (Status) && > + ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D 0)) > + { > + // > + // Out of space. > + // > + IsCommonUserVariable =3D IsUserVariable (NewVariable); > + IsCommonVariable =3D TRUE; > + > + if (IsCommonUserVariable && > + ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize= ) > + > mVariableModuleGlobal->CommonMaxUserVariableSpace)) > + { > + RecordVarErrorFlag ( > + VAR_ERROR_FLAG_USER_ERROR, > + VariableName, > + VendorGuid, > + Attributes, > + VarSize > + ); > + } > + > + if (IsCommonVariable && > + ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > + > mVariableModuleGlobal->CommonVariableSpace)) > + { > + RecordVarErrorFlag ( > + VAR_ERROR_FLAG_SYSTEM_ERROR, > + VariableName, > + VendorGuid, > + Attributes, > + VarSize > + ); > + } > + } > + } > + > +Done: > + if (!EFI_ERROR (Status)) { > + if (!VolatileFlag) { > + Offset =3D (UpdatingVariable !=3D NULL) ? (UINTN)UpdatingVariable = - > (UINTN)VarStoreBase > + : 0; > + Status =3D ProtectedVariableLibWriteFinal ( > + NewVariable, > + VarSize, > + Offset > + ); > + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { > + return Status; > + } > + > + Status =3D EFI_SUCCESS; > + } > + > + UpdateVariableInfo ( > + VariableName, > + VendorGuid, > + VolatileFlag, > + FALSE, > + TRUE, > + FALSE, > + FALSE, > + &gVariableInfo > + ); > + // > + // HOB copy of the same variable is no longer needed, no matter it h= as > + // been deleted, updated or added from/to real variable storage. > + // > + if (HobVarOnlyFlag || !VolatileFlag) { > + FlushHobVariableToFlash (VariableName, VendorGuid); > + } > + > + if (!VolatileFlag) { > + VolatileCacheInstance =3D &(VarGlobal- > >VariableRuntimeCacheContext.VariableRuntimeNvCache); > + } else { > + VolatileCacheInstance =3D &(VarGlobal- > >VariableRuntimeCacheContext.VariableRuntimeVolatileCache); > + } > + > + if (VolatileCacheInstance->Store !=3D NULL) { > + Status =3D SynchronizeRuntimeVariableCache ( > + VolatileCacheInstance, > + 0, > + VolatileCacheInstance->Store->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + } else if (Status =3D=3D EFI_ALREADY_STARTED) { > + // > + // Meaning nothing needs to be done. Just return success. > + // > + Status =3D EFI_SUCCESS; > + } > + > + return Status; > +} > + > +/** > + > + This code finds variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode, and datasize is external inp= ut. > + This function will do basic validation, before parse the data. > + > + @param VariableName Name of Variable to be found. > + @param VendorGuid Variable vendor GUID. > + @param Attributes Attribute value of the variable foun= d. > + @param DataSize Size of Data found. If size is less = than the > + data, this value contains the requir= ed size. > + @param Data The buffer to return the contents of= the variable. > May be NULL > + with a zero DataSize in order to det= ermine the size buffer > needed. > + > + @return EFI_INVALID_PARAMETER Invalid parameter. > + @return EFI_SUCCESS Find the specified variable. > + @return EFI_NOT_FOUND Not found. > + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result= . > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK Variable; > + > + if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (DataSiz= e =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (VariableName[0] =3D=3D 0) { > + return EFI_NOT_FOUND; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + Status =3D FindVariable (VariableName, VendorGuid, &Variable, > &mVariableModuleGlobal->VariableGlobal, FALSE); > + if ((Variable.CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data and its size > + // > + if (!Variable.Volatile) { > + // > + // Currently only non-volatile variable needs protection. > + // > + Status =3D ProtectedVariableLibGetByBuffer ( > + Variable.CurrPtr, > + Data, > + (UINT32 *)DataSize, > + mVariableModuleGlobal->VariableGlobal.AuthFormat > + ); > + } > + > + if (Variable.Volatile || (Status =3D=3D EFI_UNSUPPORTED)) { > + Status =3D GetVariableData (Variable.CurrPtr, Data, (UINT32 *)DataSi= ze, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + } > + > + if (!EFI_ERROR (Status)) { > + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRU= E, > FALSE, FALSE, FALSE, &gVariableInfo); > + } > + > +Done: > + if ((Status =3D=3D EFI_SUCCESS) || (Status =3D=3D EFI_BUFFER_TOO_SMALL= )) { > + if ((Attributes !=3D NULL) && (Variable.CurrPtr !=3D NULL)) { > + *Attributes =3D Variable.CurrPtr->Attributes; > + } > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + return Status; > +} > + > +/** > + > + This code Finds the Next available variable. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param VariableNameSize The size of the VariableName buffer.= The > size must be large > + enough to fit input string supplied = in VariableName buffer. > + @param VariableName Pointer to variable name. > + @param VendorGuid Variable Vendor Guid. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND The next variable was not found. > + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small fo= r > the result. > + VariableNameSize has been updated wi= th the size needed > to complete the request. > + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. > + @retval EFI_INVALID_PARAMETER VariableName is NULL. > + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. > + @retval EFI_INVALID_PARAMETER The input values of VariableName and > VendorGuid are not a name and > + GUID of an existing variable. > + @retval EFI_INVALID_PARAMETER Null-terminator is not found in the = first > VariableNameSize bytes of > + the input VariableName buffer. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetNextVariableName ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN MaxLen; > + UINTN VarNameSize; > + BOOLEAN AuthFormat; > + VARIABLE_HEADER *VariablePtr; > + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; > + > + if ((VariableNameSize =3D=3D NULL) || (VariableName =3D=3D NULL) || (V= endorGuid =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + // > + // Calculate the possible maximum length of name string, including the= Null > terminator. > + // > + MaxLen =3D *VariableNameSize / sizeof (CHAR16); > + if ((MaxLen =3D=3D 0) || (StrnLenS (VariableName, MaxLen) =3D=3D MaxLe= n)) { > + // > + // Null-terminator is not found in the first VariableNameSize bytes = of the > input VariableName buffer, > + // follow spec to return EFI_INVALID_PARAMETER. > + // > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + // > + // 0: Volatile, 1: HOB, 2: Non-Volatile. > + // The index and attributes mapping must be kept in this order as Find= Variable > + // makes use of this mapping to implement search algorithm. > + // > + VariableStoreHeader[VariableStoreTypeVolatile] =3D > (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.VolatileVariableBase; > + VariableStoreHeader[VariableStoreTypeHob] =3D (VARIABLE_STORE_HEA= DER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + VariableStoreHeader[VariableStoreTypeNv] =3D mNvVariableCache; > + > + Status =3D VariableServiceGetNextVariableInternal ( > + VariableName, > + VendorGuid, > + VariableStoreHeader, > + &VariablePtr, > + AuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + VarNameSize =3D NameSizeOfVariable (VariablePtr, AuthFormat); > + ASSERT (VarNameSize !=3D 0); > + if (VarNameSize <=3D *VariableNameSize) { > + CopyMem ( > + VariableName, > + GetVariableNamePtr (VariablePtr, AuthFormat), > + VarNameSize > + ); > + CopyMem ( > + VendorGuid, > + GetVendorGuidPtr (VariablePtr, AuthFormat), > + sizeof (EFI_GUID) > + ); > + Status =3D EFI_SUCCESS; > + } else { > + Status =3D EFI_BUFFER_TOO_SMALL; > + } > + > + *VariableNameSize =3D VarNameSize; > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + return Status; > +} > + > +/** > + > + This code sets variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode, and datasize and data are > external input. > + This function will do basic validation, before parse the data. > + This function will parse the authentication carefully to avoid securit= y issues, > like > + buffer overflow, integer overflow. > + This function will check attribute carefully to avoid authentication b= ypass. > + > + @param VariableName Name of Variable to be found. > + @param VendorGuid Variable vendor GUID. > + @param Attributes Attribute value of the variabl= e found > + @param DataSize Size of Data found. If size is= less than the > + data, this value contains the = required size. > + @param Data Data pointer. > + > + @return EFI_INVALID_PARAMETER Invalid parameter. > + @return EFI_SUCCESS Set successfully. > + @return EFI_OUT_OF_RESOURCES Resource not enough to set var= iable. > + @return EFI_NOT_FOUND Not found. > + @return EFI_WRITE_PROTECTED Variable is read-only. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceSetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + VARIABLE_POINTER_TRACK Variable; > + EFI_STATUS Status; > + VARIABLE_HEADER *NextVariable; > + EFI_PHYSICAL_ADDRESS Point; > + UINTN PayloadSize; > + BOOLEAN AuthFormat; > + > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + // > + // Check input parameters. > + // > + if ((VariableName =3D=3D NULL) || (VariableName[0] =3D=3D 0) || (Vendo= rGuid =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((DataSize !=3D 0) && (Data =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check for reserverd bit in variable attribute. > + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still > allow > + // the delete operation of common authenticated variable at user physi= cal > presence. > + // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check > to AuthVariableLib > + // > + if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | > EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) !=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check if the combination of attribute bits is valid. > + // > + if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | > EFI_VARIABLE_BOOTSERVICE_ACCESS)) =3D=3D EFI_VARIABLE_RUNTIME_ACCESS) { > + // > + // Make sure if runtime bit is set, boot service bit is set also. > + // > + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) !=3D 0) { > + return EFI_UNSUPPORTED; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) =3D=3D > EFI_VARIABLE_NON_VOLATILE) { > + // > + // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid > + // > + return EFI_INVALID_PARAMETER; > + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { > + if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) { > + // > + // Not support authenticated variable write. > + // > + return EFI_INVALID_PARAMETER; > + } > + } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) { > + if (PcdGet32 (PcdHwErrStorageSize) =3D=3D 0) { > + // > + // Not support harware error record variable variable. > + // > + return EFI_INVALID_PARAMETER; > + } > + } > + > + // > + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute > + // cannot be set both. > + // > + if ( ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) =3D=3D > EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) > + && ((Attributes & > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) =3D=3D > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) > + { > + return EFI_UNSUPPORTED; > + } > + > + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) =3D=3D > EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { > + // > + // If DataSize =3D=3D AUTHINFO_SIZE and then PayloadSize is 0. > + // Maybe it's the delete operation of common authenticated variable= at user > physical presence. > + // > + if (DataSize !=3D AUTHINFO_SIZE) { > + return EFI_UNSUPPORTED; > + } > + > + PayloadSize =3D DataSize - AUTHINFO_SIZE; > + } else if ((Attributes & > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) =3D=3D > EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { > + // > + // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor. > + // > + if ((DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA) || > + (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength = > > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo))) || > + (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength = < > OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData))) > + { > + return EFI_SECURITY_VIOLATION; > + } > + > + // > + // The VariableSpeculationBarrier() call here is to ensure the above= sanity > + // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been > completed > + // before the execution of subsequent codes. > + // > + VariableSpeculationBarrier (); > + PayloadSize =3D DataSize - AUTHINFO2_SIZE (Data); > + } else { > + PayloadSize =3D DataSize; > + } > + > + if ((UINTN)(~0) - PayloadSize < StrSize (VariableName)) { > + // > + // Prevent whole variable size overflow > + // > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The size of the VariableName, including the Unicode Null in bytes = plus > + // the DataSize is limited to maximum size of PcdGet32 > (PcdMaxHardwareErrorVariableSize) > + // bytes for HwErrRec#### variable. > + // > + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + if (StrSize (VariableName) + PayloadSize > > + PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSi= ze > (AuthFormat)) > + { > + return EFI_INVALID_PARAMETER; > + } > + } else { > + // > + // The size of the VariableName, including the Unicode Null in byte= s plus > + // the DataSize is limited to maximum size of Max(Auth|Volatile)Var= iableSize > bytes. > + // > + if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { > + if (StrSize (VariableName) + PayloadSize > > + mVariableModuleGlobal->MaxAuthVariableSize - > + GetVariableHeaderSize (AuthFormat)) > + { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Failed to set variable '%s' with Guid %g\n", > + __FUNCTION__, > + VariableName, > + VendorGuid > + )); > + DEBUG (( > + DEBUG_ERROR, > + "NameSize(0x%x) + PayloadSize(0x%x) > " > + "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n", > + StrSize (VariableName), > + PayloadSize, > + mVariableModuleGlobal->MaxAuthVariableSize, > + GetVariableHeaderSize (AuthFormat) > + )); > + return EFI_INVALID_PARAMETER; > + } > + } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { > + if (StrSize (VariableName) + PayloadSize > > + mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize > (AuthFormat)) > + { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Failed to set variable '%s' with Guid %g\n", > + __FUNCTION__, > + VariableName, > + VendorGuid > + )); > + DEBUG (( > + DEBUG_ERROR, > + "NameSize(0x%x) + PayloadSize(0x%x) > " > + "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n", > + StrSize (VariableName), > + PayloadSize, > + mVariableModuleGlobal->MaxVariableSize, > + GetVariableHeaderSize (AuthFormat) > + )); > + return EFI_INVALID_PARAMETER; > + } > + } else { > + if (StrSize (VariableName) + PayloadSize > > + mVariableModuleGlobal->MaxVolatileVariableSize - > GetVariableHeaderSize (AuthFormat)) > + { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Failed to set variable '%s' with Guid %g\n", > + __FUNCTION__, > + VariableName, > + VendorGuid > + )); > + DEBUG (( > + DEBUG_ERROR, > + "NameSize(0x%x) + PayloadSize(0x%x) > " > + "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n", > + StrSize (VariableName), > + PayloadSize, > + mVariableModuleGlobal->MaxVolatileVariableSize, > + GetVariableHeaderSize (AuthFormat) > + )); > + return EFI_INVALID_PARAMETER; > + } > + } > + } > + > + // > + // Special Handling for MOR Lock variable. > + // > + Status =3D SetVariableCheckHandlerMor (VariableName, VendorGuid, Attri= butes, > PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize)); > + if (Status =3D=3D EFI_ALREADY_STARTED) { > + // > + // EFI_ALREADY_STARTED means the SetVariable() action is handled ins= ide of > SetVariableCheckHandlerMor(). > + // Variable driver can just return SUCCESS. > + // > + return EFI_SUCCESS; > + } > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attr= ibutes, > PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize), mRequestSour= ce); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + // > + // Consider reentrant in MCA/INIT/NMI. It needs be reupdated. > + // > + if (1 < InterlockedIncrement (&mVariableModuleGlobal- > >VariableGlobal.ReentrantState)) { > + Point =3D mVariableModuleGlobal->VariableGlobal.NonVolatileVariableB= ase; > + // > + // Parse non-volatile variable data and get last variable offset. > + // > + NextVariable =3D GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Po= int); > + while (IsValidVariableHeader (NextVariable, GetEndPointer > ((VARIABLE_STORE_HEADER *)(UINTN)Point), AuthFormat)) { > + NextVariable =3D GetNextVariablePtr (NextVariable, AuthFormat); > + } > + > + mVariableModuleGlobal->NonVolatileLastVariableOffset =3D > (UINTN)NextVariable - (UINTN)Point; > + } > + > + // > + // Check whether the input variable is already existed. > + // > + Status =3D FindVariable (VariableName, VendorGuid, &Variable, > &mVariableModuleGlobal->VariableGlobal, TRUE); > + if (!EFI_ERROR (Status)) { > + if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) = =3D=3D 0) > && AtRuntime ()) { > + Status =3D EFI_WRITE_PROTECTED; > + goto Done; > + } > + > + if ((Attributes !=3D 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRIT= E)) !=3D > Variable.CurrPtr->Attributes)) { > + // > + // If a preexisting variable is rewritten with different attribute= s, SetVariable() > shall not > + // modify the variable and shall return EFI_INVALID_PARAMETER. Two > exceptions to this rule: > + // 1. No access attributes specified > + // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE > + // > + Status =3D EFI_INVALID_PARAMETER; > + DEBUG ((DEBUG_INFO, "[Variable]: Rewritten a preexisting variable(= 0x%08x) > with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attribute= s, > Attributes, VendorGuid, VariableName)); > + goto Done; > + } > + } > + > + if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) { > + // > + // Hook the operation of setting PlatformLangCodes/PlatformLang and > LangCodes/Lang. > + // > + Status =3D AutoUpdateLangVariable (VariableName, Data, DataSize); > + if (EFI_ERROR (Status)) { > + // > + // The auto update operation failed, directly return to avoid inco= nsistency > between PlatformLang and Lang. > + // > + goto Done; > + } > + } > + > + if (mVariableModuleGlobal->VariableGlobal.AuthSupport) { > + Status =3D AuthVariableLibProcessVariable (VariableName, VendorGuid,= Data, > DataSize, Attributes); > + } else { > + Status =3D UpdateVariable (VariableName, VendorGuid, Data, DataSize, > Attributes, 0, 0, &Variable, NULL); > + } > + > +Done: > + InterlockedDecrement (&mVariableModuleGlobal- > >VariableGlobal.ReentrantState); > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + if (!AtRuntime ()) { > + if (!EFI_ERROR (Status)) { > + SecureBootHook ( > + VariableName, > + VendorGuid > + ); > + } > + } > + > + return Status; > +} > + > +/** > + > + This code returns information about the EFI variables. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param Attributes Attributes bitmask to specify th= e type of > variables > + on which to return information. > + @param MaximumVariableStorageSize Pointer to the maximum size of t= he > storage space available > + for the EFI variables associated= with the attributes > specified. > + @param RemainingVariableStorageSize Pointer to the remaining size of= the > storage space available > + for EFI variables associated wit= h the attributes specified. > + @param MaximumVariableSize Pointer to the maximum size of a= n > individual EFI variables > + associated with the attributes s= pecified. > + > + @return EFI_SUCCESS Query successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceQueryVariableInfoInternal ( > + IN UINT32 Attributes, > + OUT UINT64 *MaximumVariableStorageSize, > + OUT UINT64 *RemainingVariableStorageSize, > + OUT UINT64 *MaximumVariableSize > + ) > +{ > + VARIABLE_HEADER *Variable; > + VARIABLE_HEADER *NextVariable; > + UINT64 VariableSize; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + UINT64 CommonVariableTotalSize; > + UINT64 HwErrVariableTotalSize; > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK VariablePtrTrack; > + > + CommonVariableTotalSize =3D 0; > + HwErrVariableTotalSize =3D 0; > + > + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) =3D=3D 0) { > + // > + // Query is Volatile related. > + // > + VariableStoreHeader =3D (VARIABLE_STORE_HEADER > *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); > + } else { > + // > + // Query is Non-Volatile related. > + // > + VariableStoreHeader =3D mNvVariableCache; > + } > + > + // > + // Now let's fill *MaximumVariableStorageSize > *RemainingVariableStorageSize > + // with the storage size (excluding the storage header size). > + // > + *MaximumVariableStorageSize =3D VariableStoreHeader->Size - sizeof > (VARIABLE_STORE_HEADER); > + > + // > + // Harware error record variable needs larger size. > + // > + if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_HARDWARE_ERROR_RECORD)) =3D=3D > (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) > { > + *MaximumVariableStorageSize =3D PcdGet32 (PcdHwErrStorageSize); > + *MaximumVariableSize =3D PcdGet32 (PcdMaxHardwareErrorVariab= leSize) > - > + GetVariableHeaderSize (mVariableModule= Global- > >VariableGlobal.AuthFormat); > + } else { > + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { > + if (AtRuntime ()) { > + *MaximumVariableStorageSize =3D mVariableModuleGlobal- > >CommonRuntimeVariableSpace; > + } else { > + *MaximumVariableStorageSize =3D mVariableModuleGlobal- > >CommonVariableSpace; > + } > + } > + > + // > + // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with t= he > exception of the variable header size. > + // > + if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { > + *MaximumVariableSize =3D mVariableModuleGlobal->MaxAuthVariableSi= ze - > + GetVariableHeaderSize (mVariableModuleGloba= l- > >VariableGlobal.AuthFormat); > + } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0) { > + *MaximumVariableSize =3D mVariableModuleGlobal->MaxVariableSize - > + GetVariableHeaderSize (mVariableModuleGloba= l- > >VariableGlobal.AuthFormat); > + } else { > + *MaximumVariableSize =3D mVariableModuleGlobal- > >MaxVolatileVariableSize - > + GetVariableHeaderSize (mVariableModuleGloba= l- > >VariableGlobal.AuthFormat); > + } > + } > + > + // > + // Point to the starting address of the variables. > + // > + Variable =3D GetStartPointer (VariableStoreHeader); > + > + // > + // Now walk through the related variable store. > + // > + while (IsValidVariableHeader ( > + Variable, > + GetEndPointer (VariableStoreHeader), > + mVariableModuleGlobal->VariableGlobal.AuthFormat > + )) > + { > + NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlobal= - > >VariableGlobal.AuthFormat); > + VariableSize =3D (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variab= le; > + > + if (AtRuntime ()) { > + // > + // We don't take the state of the variables in mind > + // when calculating RemainingVariableStorageSize, > + // since the space occupied by variables not marked with > + // VAR_ADDED is not allowed to be reclaimed in Runtime. > + // > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) = =3D=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + HwErrVariableTotalSize +=3D VariableSize; > + } else { > + CommonVariableTotalSize +=3D VariableSize; > + } > + } else { > + // > + // Only care about Variables with State VAR_ADDED, because > + // the space not marked as VAR_ADDED is reclaimable now. > + // > + if (Variable->State =3D=3D VAR_ADDED) { > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) > =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + HwErrVariableTotalSize +=3D VariableSize; > + } else { > + CommonVariableTotalSize +=3D VariableSize; > + } > + } else if (Variable->State =3D=3D (VAR_IN_DELETED_TRANSITION & VAR= _ADDED)) > { > + // > + // If it is a IN_DELETED_TRANSITION variable, > + // and there is not also a same ADDED one at the same time, > + // this IN_DELETED_TRANSITION variable is valid. > + // > + VariablePtrTrack.StartPtr =3D GetStartPointer (VariableStoreHead= er); > + VariablePtrTrack.EndPtr =3D GetEndPointer (VariableStoreHeader= ); > + Status =3D FindVariableEx ( > + GetVariableNamePtr (Variable, mVar= iableModuleGlobal- > >VariableGlobal.AuthFormat), > + GetVendorGuidPtr (Variable, mVaria= bleModuleGlobal- > >VariableGlobal.AuthFormat), > + FALSE, > + &VariablePtrTrack, > + mVariableModuleGlobal->VariableGlo= bal.AuthFormat > + ); > + if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State !=3D > VAR_ADDED)) { > + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD= ) > =3D=3D EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + HwErrVariableTotalSize +=3D VariableSize; > + } else { > + CommonVariableTotalSize +=3D VariableSize; > + } > + } > + } > + } > + > + // > + // Go to the next one. > + // > + Variable =3D NextVariable; > + } > + > + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) =3D=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + *RemainingVariableStorageSize =3D *MaximumVariableStorageSize - > HwErrVariableTotalSize; > + } else { > + if (*MaximumVariableStorageSize < CommonVariableTotalSize) { > + *RemainingVariableStorageSize =3D 0; > + } else { > + *RemainingVariableStorageSize =3D *MaximumVariableStorageSize - > CommonVariableTotalSize; > + } > + } > + > + if (*RemainingVariableStorageSize < GetVariableHeaderSize > (mVariableModuleGlobal->VariableGlobal.AuthFormat)) { > + *MaximumVariableSize =3D 0; > + } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize > (mVariableModuleGlobal->VariableGlobal.AuthFormat)) < > + *MaximumVariableSize > + ) > + { > + *MaximumVariableSize =3D *RemainingVariableStorageSize - > + GetVariableHeaderSize (mVariableModuleGlobal- > >VariableGlobal.AuthFormat); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + This code returns information about the EFI variables. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param Attributes Attributes bitmask to specify th= e type of > variables > + on which to return information. > + @param MaximumVariableStorageSize Pointer to the maximum size of t= he > storage space available > + for the EFI variables associated= with the attributes > specified. > + @param RemainingVariableStorageSize Pointer to the remaining size of= the > storage space available > + for EFI variables associated wit= h the attributes specified. > + @param MaximumVariableSize Pointer to the maximum size of a= n > individual EFI variables > + associated with the attributes s= pecified. > + > + @return EFI_INVALID_PARAMETER An invalid combination of attrib= ute > bits was supplied. > + @return EFI_SUCCESS Query successfully. > + @return EFI_UNSUPPORTED The attribute is not supported o= n this > platform. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceQueryVariableInfo ( > + IN UINT32 Attributes, > + OUT UINT64 *MaximumVariableStorageSize, > + OUT UINT64 *RemainingVariableStorageSize, > + OUT UINT64 *MaximumVariableSize > + ) > +{ > + EFI_STATUS Status; > + > + if ((MaximumVariableStorageSize =3D=3D NULL) || (RemainingVariableStor= ageSize > =3D=3D NULL) || (MaximumVariableSize =3D=3D NULL) || (Attributes =3D=3D 0= )) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) !=3D 0) { > + // > + // Deprecated attribute, make this check as highest priority. > + // > + return EFI_UNSUPPORTED; > + } > + > + if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) =3D=3D 0) { > + // > + // Make sure the Attributes combination is supported by the platform= . > + // > + return EFI_UNSUPPORTED; > + } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) =3D=3D > EFI_VARIABLE_NON_VOLATILE) { > + // > + // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid > + // > + return EFI_INVALID_PARAMETER; > + } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | > EFI_VARIABLE_BOOTSERVICE_ACCESS)) =3D=3D EFI_VARIABLE_RUNTIME_ACCESS) { > + // > + // Make sure if runtime bit is set, boot service bit is set also. > + // > + return EFI_INVALID_PARAMETER; > + } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS)= =3D=3D > 0)) { > + // > + // Make sure RT Attribute is set if we are in Runtime phase. > + // > + return EFI_INVALID_PARAMETER; > + } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_HARDWARE_ERROR_RECORD)) =3D=3D > EFI_VARIABLE_HARDWARE_ERROR_RECORD) { > + // > + // Make sure Hw Attribute is set with NV. > + // > + return EFI_INVALID_PARAMETER; > + } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) !=3D 0) { > + if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) { > + // > + // Not support authenticated variable write. > + // > + return EFI_UNSUPPORTED; > + } > + } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) !=3D 0) { > + if (PcdGet32 (PcdHwErrStorageSize) =3D=3D 0) { > + // > + // Not support harware error record variable variable. > + // > + return EFI_UNSUPPORTED; > + } > + } > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + Status =3D VariableServiceQueryVariableInfoInternal ( > + Attributes, > + MaximumVariableStorageSize, > + RemainingVariableStorageSize, > + MaximumVariableSize > + ); > + > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + return Status; > +} > + > +/** > + This function reclaims variable storage if free size is below the thre= shold. > + > + Caution: This function may be invoked at SMM mode. > + Care must be taken to make sure not security issue. > + > +**/ > +VOID > +ReclaimForOS ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINTN RemainingCommonRuntimeVariableSpace; > + UINTN RemainingHwErrVariableSpace; > + STATIC BOOLEAN Reclaimed; > + > + // > + // This function will be called only once at EndOfDxe or ReadyToBoot e= vent. > + // > + if (Reclaimed) { > + return; > + } > + > + Reclaimed =3D TRUE; > + > + Status =3D EFI_SUCCESS; > + > + if (mVariableModuleGlobal->CommonRuntimeVariableSpace < > mVariableModuleGlobal->CommonVariableTotalSize) { > + RemainingCommonRuntimeVariableSpace =3D 0; > + } else { > + RemainingCommonRuntimeVariableSpace =3D mVariableModuleGlobal- > >CommonRuntimeVariableSpace - mVariableModuleGlobal- > >CommonVariableTotalSize; > + } > + > + RemainingHwErrVariableSpace =3D PcdGet32 (PcdHwErrStorageSize) - > mVariableModuleGlobal->HwErrVariableTotalSize; > + > + // > + // Check if the free area is below a threshold. > + // > + if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal- > >MaxVariableSize) || > + (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal- > >MaxAuthVariableSize)) || > + ((PcdGet32 (PcdHwErrStorageSize) !=3D 0) && > + (RemainingHwErrVariableSpace < PcdGet32 > (PcdMaxHardwareErrorVariableSize)))) > + { > + Status =3D Reclaim ( > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariable= Base, > + &mVariableModuleGlobal->NonVolatileLastVariableOffset, > + FALSE, > + NULL, > + NULL, > + 0 > + ); > + ASSERT_EFI_ERROR (Status); > + } > +} > + > +/** > + Get maximum variable size, covering both non-volatile and volatile var= iables. > + > + @return Maximum variable size. > + > +**/ > +UINTN > +GetMaxVariableSize ( > + VOID > + ) > +{ > + UINTN MaxVariableSize; > + > + MaxVariableSize =3D GetNonVolatileMaxVariableSize (); > + // > + // The condition below fails implicitly if PcdMaxVolatileVariableSize = equals > + // the default zero value. > + // > + if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) { > + MaxVariableSize =3D PcdGet32 (PcdMaxVolatileVariableSize); > + } > + > + return MaxVariableSize; > +} > + > +/** > + Flush the HOB variable to flash. > + > + @param[in] VariableName Name of variable has been updated or del= eted. > + @param[in] VendorGuid Guid of variable has been updated or del= eted. > + > +**/ > +VOID > +FlushHobVariableToFlash ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + VARIABLE_HEADER *Variable; > + VOID *VariableData; > + VARIABLE_POINTER_TRACK VariablePtrTrack; > + BOOLEAN ErrorFlag; > + BOOLEAN AuthFormat; > + > + ErrorFlag =3D FALSE; > + AuthFormat =3D mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + // > + // Flush the HOB variable to flash. > + // > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0) { > + VariableStoreHeader =3D (VARIABLE_STORE_HEADER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + // > + // Set HobVariableBase to 0, it can avoid SetVariable to call back. > + // > + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D 0; > + for ( Variable =3D GetStartPointer (VariableStoreHeader) > + ; IsValidVariableHeader (Variable, GetEndPointer (VariableStor= eHeader), > AuthFormat) > + ; Variable =3D GetNextVariablePtr (Variable, AuthFormat) > + ) > + { > + if (Variable->State !=3D VAR_ADDED) { > + // > + // The HOB variable has been set to DELETED state in local. > + // > + continue; > + } > + > + ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) !=3D 0)= ; > + if ((VendorGuid =3D=3D NULL) || (VariableName =3D=3D NULL) || > + !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthForm= at)) || > + (StrCmp (VariableName, GetVariableNamePtr (Variable, AuthForma= t)) !=3D > 0)) > + { > + VariableData =3D GetVariableDataPtr (Variable, AuthFormat); > + FindVariable ( > + GetVariableNamePtr (Variable, AuthFormat), > + GetVendorGuidPtr (Variable, AuthFormat), > + &VariablePtrTrack, > + &mVariableModuleGlobal->VariableGlobal, > + FALSE > + ); > + Status =3D UpdateVariable ( > + GetVariableNamePtr (Variable, AuthFormat), > + GetVendorGuidPtr (Variable, AuthFormat), > + VariableData, > + DataSizeOfVariable (Variable, AuthFormat), > + Variable->Attributes, > + 0, > + 0, > + &VariablePtrTrack, > + NULL > + ); > + DEBUG (( > + DEBUG_INFO, > + "Variable driver flush the HOB variable to flash: %g %s %r\n", > + GetVendorGuidPtr (Variable, AuthFormat), > + GetVariableNamePtr (Variable, AuthFormat), > + Status > + )); > + } else { > + // > + // The updated or deleted variable is matched with this HOB vari= able. > + // Don't break here because we will try to set other HOB variabl= es > + // since this variable could be set successfully. > + // > + Status =3D EFI_SUCCESS; > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // If set variable successful, or the updated or deleted variabl= e is matched > with the HOB variable, > + // set the HOB variable to DELETED state in local. > + // > + DEBUG (( > + DEBUG_INFO, > + "Variable driver set the HOB variable to DELETED state in loca= l: %g %s\n", > + GetVendorGuidPtr (Variable, AuthFormat), > + GetVariableNamePtr (Variable, AuthFormat) > + )); > + Variable->State &=3D VAR_DELETED; > + } else { > + ErrorFlag =3D TRUE; > + } > + } > + > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor > e !=3D NULL) { > + Status =3D SynchronizeRuntimeVariableCache ( > + &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache, > + 0, > + mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Stor > e->Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + > + if (ErrorFlag) { > + // > + // We still have HOB variable(s) not flushed in flash. > + // > + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D > (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStoreHeader; > + } else { > + // > + // All HOB variables have been flushed in flash. > + // > + DEBUG ((DEBUG_INFO, "Variable driver: all HOB variables have been > flushed in flash.\n")); > + if (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete !=3D NULL) { > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) =3D TRUE; > + } > + > + if (!AtRuntime ()) { > + FreePool ((VOID *)VariableStoreHeader); > + } > + } > + } > +} > + > +/** > + Initializes variable write service. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval Others Fail to initialize the variable service. > + > +**/ > +EFI_STATUS > +VariableWriteServiceInitialize ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + UINT8 Data; > + VARIABLE_ENTRY_PROPERTY *VariableEntry; > + > + AcquireLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + // > + // Check if the free area is really free. > + // > + for (Index =3D mVariableModuleGlobal->NonVolatileLastVariableOffset; I= ndex < > mNvVariableCache->Size; Index++) { > + Data =3D ((UINT8 *)mNvVariableCache)[Index]; > + if (Data !=3D 0xff) { > + // > + // There must be something wrong in variable store, do reclaim ope= ration. > + // > + Status =3D Reclaim ( > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariab= leBase, > + &mVariableModuleGlobal->NonVolatileLastVariableOffset, > + FALSE, > + NULL, > + NULL, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + return Status; > + } > + > + break; > + } > + } > + > + FlushHobVariableToFlash (NULL, NULL); > + > + Status =3D EFI_SUCCESS; > + ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut)); > + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { > + // > + // Authenticated variable initialize. > + // > + mAuthContextIn.StructSize =3D sizeof (AUTH_VAR_LIB_CONTEXT_= IN); > + mAuthContextIn.MaxAuthVariableSize =3D mVariableModuleGlobal- > >MaxAuthVariableSize - > + GetVariableHeaderSize (mVariabl= eModuleGlobal- > >VariableGlobal.AuthFormat); > + Status =3D AuthVariableLibInitialize (&mAuthContextIn, &mAuthContext= Out); > + if (!EFI_ERROR (Status)) { > + DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable > support!\n")); > + mVariableModuleGlobal->VariableGlobal.AuthSupport =3D TRUE; > + if (mAuthContextOut.AuthVarEntry !=3D NULL) { > + for (Index =3D 0; Index < mAuthContextOut.AuthVarEntryCount; Ind= ex++) { > + VariableEntry =3D &mAuthContextOut.AuthVarEntry[Index]; > + Status =3D VarCheckLibVariablePropertySet ( > + VariableEntry->Name, > + VariableEntry->Guid, > + &VariableEntry->VariableProperty > + ); > + ASSERT_EFI_ERROR (Status); > + } > + } > + } else if (Status =3D=3D EFI_UNSUPPORTED) { > + DEBUG ((DEBUG_INFO, "NOTICE - AuthVariableLibInitialize() returns = %r!\n", > Status)); > + DEBUG ((DEBUG_INFO, "Variable driver will continue to work without= auth > variable support!\n")); > + mVariableModuleGlobal->VariableGlobal.AuthSupport =3D FALSE; > + Status =3D EFI_SUCCESS; > + } > + } > + > + if (!EFI_ERROR (Status)) { > + for (Index =3D 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index= ++) { > + VariableEntry =3D &mVariableEntryProperty[Index]; > + Status =3D VarCheckLibVariablePropertySet (VariableEntry->N= ame, > VariableEntry->Guid, &VariableEntry->VariableProperty); > + ASSERT_EFI_ERROR (Status); > + } > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock); > + > + // > + // Initialize MOR Lock variable. > + // > + MorLockInit (); > + > + return Status; > +} > + > +/** > + Convert normal variable storage to the allocated auth variable storage= . > + > + @param[in] NormalVarStorage Pointer to the normal variable storage > header > + > + @retval the allocated auth variable storage > +**/ > +VOID * > +ConvertNormalVarStorageToAuthVarStorage ( > + VARIABLE_STORE_HEADER *NormalVarStorage > + ) > +{ > + VARIABLE_HEADER *StartPtr; > + UINT8 *NextPtr; > + VARIABLE_HEADER *EndPtr; > + UINTN AuthVarStorageSize; > + AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr; > + VARIABLE_STORE_HEADER *AuthVarStorage; > + > + AuthVarStorageSize =3D sizeof (VARIABLE_STORE_HEADER); > + // > + // Set AuthFormat as FALSE for normal variable storage > + // > + mVariableModuleGlobal->VariableGlobal.AuthFormat =3D FALSE; > + > + // > + // Calculate Auth Variable Storage Size > + // > + StartPtr =3D GetStartPointer (NormalVarStorage); > + EndPtr =3D GetEndPointer (NormalVarStorage); > + while (StartPtr < EndPtr) { > + if (StartPtr->State =3D=3D VAR_ADDED) { > + AuthVarStorageSize =3D HEADER_ALIGN (AuthVarStorageSize); > + AuthVarStorageSize +=3D sizeof (AUTHENTICATED_VARIABLE_HEADER); > + AuthVarStorageSize +=3D StartPtr->NameSize + GET_PAD_SIZE (StartPt= r- > >NameSize); > + AuthVarStorageSize +=3D StartPtr->DataSize + GET_PAD_SIZE (StartPt= r- > >DataSize); > + } > + > + StartPtr =3D GetNextVariablePtr (StartPtr, mVariableModuleGlobal- > >VariableGlobal.AuthFormat); > + } > + > + // > + // Allocate Runtime memory for Auth Variable Storage > + // > + AuthVarStorage =3D AllocateRuntimeZeroPool (AuthVarStorageSize); > + ASSERT (AuthVarStorage !=3D NULL); > + if (AuthVarStorage =3D=3D NULL) { > + return NULL; > + } > + > + // > + // Copy Variable from Normal storage to Auth storage > + // > + StartPtr =3D GetStartPointer (NormalVarStorage); > + EndPtr =3D GetEndPointer (NormalVarStorage); > + AuthStartPtr =3D (AUTHENTICATED_VARIABLE_HEADER *)GetStartPointer > (AuthVarStorage); > + while (StartPtr < EndPtr) { > + if (StartPtr->State =3D=3D VAR_ADDED) { > + AuthStartPtr =3D (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN > (AuthStartPtr); > + // > + // Copy Variable Header > + // > + AuthStartPtr->StartId =3D StartPtr->StartId; > + AuthStartPtr->State =3D StartPtr->State; > + AuthStartPtr->Attributes =3D StartPtr->Attributes; > + AuthStartPtr->NameSize =3D StartPtr->NameSize; > + AuthStartPtr->DataSize =3D StartPtr->DataSize; > + CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid); > + // > + // Copy Variable Name > + // > + NextPtr =3D (UINT8 *)(AuthStartPtr + 1); > + CopyMem ( > + NextPtr, > + GetVariableNamePtr (StartPtr, mVariableModuleGlobal- > >VariableGlobal.AuthFormat), > + AuthStartPtr->NameSize > + ); > + // > + // Copy Variable Data > + // > + NextPtr =3D NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthS= tartPtr- > >NameSize); > + CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlo= bal- > >VariableGlobal.AuthFormat), AuthStartPtr->DataSize); > + // > + // Go to next variable > + // > + AuthStartPtr =3D (AUTHENTICATED_VARIABLE_HEADER *)(NextPtr + > AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize)); > + } > + > + StartPtr =3D GetNextVariablePtr (StartPtr, mVariableModuleGlobal- > >VariableGlobal.AuthFormat); > + } > + > + // > + // Update Auth Storage Header > + // > + AuthVarStorage->Format =3D NormalVarStorage->Format; > + AuthVarStorage->State =3D NormalVarStorage->State; > + AuthVarStorage->Size =3D (UINT32)((UINTN)AuthStartPtr - > (UINTN)AuthVarStorage); > + CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid); > + ASSERT (AuthVarStorage->Size <=3D AuthVarStorageSize); > + > + // > + // Restore AuthFormat > + // > + mVariableModuleGlobal->VariableGlobal.AuthFormat =3D TRUE; > + return AuthVarStorage; > +} > + > +/** > + Get HOB variable store. > + > + @param[in] VariableGuid NV variable store signature. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + > +**/ > +EFI_STATUS > +GetHobVariableStore ( > + IN EFI_GUID *VariableGuid > + ) > +{ > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + UINT64 VariableStoreLength; > + EFI_HOB_GUID_TYPE *GuidHob; > + BOOLEAN NeedConvertNormalToAuth; > + > + // > + // Make sure there is no more than one Variable HOB. > + // > + DEBUG_CODE_BEGIN (); > + GuidHob =3D GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); > + if (GuidHob !=3D NULL) { > + if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB > (GuidHob)) !=3D NULL)) { > + DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n")); > + ASSERT (FALSE); > + } else if (GetFirstGuidHob (&gEfiVariableGuid) !=3D NULL) { > + DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable > HOBs\n")); > + ASSERT (FALSE); > + } > + } else { > + GuidHob =3D GetFirstGuidHob (&gEfiVariableGuid); > + if (GuidHob !=3D NULL) { > + if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != =3D > NULL)) { > + DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"))= ; > + ASSERT (FALSE); > + } > + } > + } > + > + DEBUG_CODE_END (); > + > + // > + // Combinations supported: > + // 1. Normal NV variable store + > + // Normal HOB variable store > + // 2. Auth NV variable store + > + // Auth HOB variable store > + // 3. Auth NV variable store + > + // Normal HOB variable store (code will convert it to Auth Format) > + // > + NeedConvertNormalToAuth =3D FALSE; > + GuidHob =3D GetFirstGuidHob (VariableGuid); > + if ((GuidHob =3D=3D NULL) && (VariableGuid =3D=3D &gEfiAuthenticatedVa= riableGuid)) { > + // > + // Try getting it from normal variable HOB > + // > + GuidHob =3D GetFirstGuidHob (&gEfiVariableGuid); > + NeedConvertNormalToAuth =3D TRUE; > + } > + > + if (GuidHob !=3D NULL) { > + VariableStoreHeader =3D GET_GUID_HOB_DATA (GuidHob); > + VariableStoreLength =3D GuidHob->Header.HobLength - sizeof > (EFI_HOB_GUID_TYPE); > + if (GetVariableStoreStatus (VariableStoreHeader) =3D=3D EfiValid) { > + if (!NeedConvertNormalToAuth) { > + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D > (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimeCopyPool > ((UINTN)VariableStoreLength, (VOID *)VariableStoreHeader); > + } else { > + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D > (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertNormalVarStorageToAuthVarStorage > ((VOID *)VariableStoreHeader); > + } > + > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D=3D 0= ) { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + DEBUG ((DEBUG_ERROR, "HOB Variable Store header is corrupted!\n"))= ; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Initializes variable store area for non-volatile and volatile variable= . > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + > +**/ > +EFI_STATUS > +VariableCommonInitialize ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_STORE_HEADER *VolatileVariableStore; > + UINTN ScratchSize; > + EFI_GUID *VariableGuid; > + > + // > + // Allocate runtime memory for variable driver global structure. > + // > + mVariableModuleGlobal =3D AllocateRuntimeZeroPool (sizeof > (VARIABLE_MODULE_GLOBAL)); > + if (mVariableModuleGlobal =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeLock (&mVariableModuleGlobal- > >VariableGlobal.VariableServicesLock, TPL_NOTIFY); > + > + // > + // Init non-volatile variable store. > + // > + Status =3D InitNonVolatileVariableStore (); > + if (EFI_ERROR (Status)) { > + FreePool (mVariableModuleGlobal); > + return Status; > + } > + > + // > + // mVariableModuleGlobal->VariableGlobal.AuthFormat > + // has been initialized in InitNonVolatileVariableStore(). > + // > + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { > + DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable > format!\n")); > + // > + // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() = will initialize > it. > + // > + mVariableModuleGlobal->VariableGlobal.AuthSupport =3D FALSE; > + VariableGuid =3D &gEfiAuthentic= atedVariableGuid; > + } else { > + DEBUG ((DEBUG_INFO, "Variable driver will work without auth variable > support!\n")); > + mVariableModuleGlobal->VariableGlobal.AuthSupport =3D FALSE; > + VariableGuid =3D &gEfiVariableG= uid; > + } > + > + // > + // Get HOB variable store. > + // > + Status =3D GetHobVariableStore (VariableGuid); > + if (EFI_ERROR (Status)) { > + if (mNvFvHeaderCache !=3D NULL) { > + FreePool (mNvFvHeaderCache); > + } > + > + FreePool (mVariableModuleGlobal); > + return Status; > + } > + > + mVariableModuleGlobal->MaxVolatileVariableSize =3D ((PcdGet32 > (PcdMaxVolatileVariableSize) !=3D 0) ? > + PcdGet32 (PcdMaxVola= tileVariableSize) : > + mVariableModuleGloba= l->MaxVariableSize > + ); > + // > + // Allocate memory for volatile variable store, note that there is a s= cratch > space to store scratch data. > + // > + ScratchSize =3D GetMaxVariableSize () * 2= ; > + mVariableModuleGlobal->ScratchBufferSize =3D ScratchSize; > + VolatileVariableStore =3D AllocateRuntimePool (PcdG= et32 > (PcdVariableStoreSize) + ScratchSize); > + if (VolatileVariableStore =3D=3D NULL) { > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0) { > + FreePool ((VOID *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.HobVariableBase); > + } > + > + if (mNvFvHeaderCache !=3D NULL) { > + FreePool (mNvFvHeaderCache); > + } > + > + FreePool (mVariableModuleGlobal); > + return EFI_OUT_OF_RESOURCES; > + } > + > + SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + Scrat= chSize, > 0xff); > + > + // > + // Initialize Variable Specific Data. > + // > + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase =3D > (EFI_PHYSICAL_ADDRESS)(UINTN)VolatileVariableStore; > + mVariableModuleGlobal->VolatileLastVariableOffset =3D > (UINTN)GetStartPointer (VolatileVariableStore) - (UINTN)VolatileVariableS= tore; > + > + CopyGuid (&VolatileVariableStore->Signature, VariableGuid); > + VolatileVariableStore->Size =3D PcdGet32 (PcdVariableStoreSize); > + VolatileVariableStore->Format =3D VARIABLE_STORE_FORMATTED; > + VolatileVariableStore->State =3D VARIABLE_STORE_HEALTHY; > + VolatileVariableStore->Reserved =3D 0; > + VolatileVariableStore->Reserved1 =3D 0; > + > + return EFI_SUCCESS; > +} > + > +/** > + Get the proper fvb handle and/or fvb protocol by the given Flash addre= ss. > + > + @param[in] Address The Flash address. > + @param[out] FvbHandle In output, if it is not NULL, it points to t= he proper > FVB handle. > + @param[out] FvbProtocol In output, if it is not NULL, it points to t= he proper > FVB protocol. > + > +**/ > +EFI_STATUS > +GetFvbInfoByAddress ( > + IN EFI_PHYSICAL_ADDRESS Address, > + OUT EFI_HANDLE *FvbHandle OPTIONAL, > + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE *HandleBuffer; > + UINTN HandleCount; > + UINTN Index; > + EFI_PHYSICAL_ADDRESS FvbBaseAddress; > + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; > + EFI_FVB_ATTRIBUTES_2 Attributes; > + UINTN BlockSize; > + UINTN NumberOfBlocks; > + > + HandleBuffer =3D NULL; > + // > + // Get all FVB handles. > + // > + Status =3D GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); > + if (EFI_ERROR (Status)) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Get the FVB to access variable store. > + // > + Fvb =3D NULL; > + for (Index =3D 0; Index < HandleCount; Index +=3D 1, Status =3D EFI_NO= T_FOUND, > Fvb =3D NULL) { > + Status =3D GetFvbByHandle (HandleBuffer[Index], &Fvb); > + if (EFI_ERROR (Status)) { > + Status =3D EFI_NOT_FOUND; > + break; > + } > + > + // > + // Ensure this FVB protocol supported Write operation. > + // > + Status =3D Fvb->GetAttributes (Fvb, &Attributes); > + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) =3D= =3D 0)) { > + continue; > + } > + > + // > + // Compare the address and select the right one. > + // > + Status =3D Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); > + if (EFI_ERROR (Status)) { > + continue; > + } > + > + // > + // Assume one FVB has one type of BlockSize. > + // > + Status =3D Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks); > + if (EFI_ERROR (Status)) { > + continue; > + } > + > + if ((Address >=3D FvbBaseAddress) && (Address < (FvbBaseAddress + Bl= ockSize * > NumberOfBlocks))) { > + if (FvbHandle !=3D NULL) { > + *FvbHandle =3D HandleBuffer[Index]; > + } > + > + if (FvbProtocol !=3D NULL) { > + *FvbProtocol =3D Fvb; > + } > + > + Status =3D EFI_SUCCESS; > + break; > + } > + } > + > + FreePool (HandleBuffer); > + > + if (Fvb =3D=3D NULL) { > + Status =3D EFI_NOT_FOUND; > + } > + > + return Status; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c > new file mode 100644 > index 000000000000..4595bf8c9d02 > --- /dev/null > +++ b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableDxe.c > @@ -0,0 +1,670 @@ > +/** @file > + Implement all four UEFI Runtime Variable services for the nonvolatile > + and volatile storage space and install variable architecture protocol. > + > +Copyright (C) 2013, Red Hat, Inc. > +Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP
> +Copyright (c) Microsoft Corporation. > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > + > +#include > +#include > +#include "VariableParsing.h" > + > +EFI_STATUS > +EFIAPI > +ProtocolIsVariablePolicyEnabled ( > + OUT BOOLEAN *State > + ); > + > +EFI_HANDLE mHandle =3D NULL; > +EFI_EVENT mVirtualAddressChangeEvent =3D NULL; > +VOID *mFtwRegistration =3D NULL; > +VOID ***mVarCheckAddressPointer =3D NULL; > +UINTN mVarCheckAddressPointerCount =3D 0; > +EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock =3D > { VariableLockRequestToLock }; > +EDKII_VARIABLE_POLICY_PROTOCOL mVariablePolicyProtocol =3D { > + EDKII_VARIABLE_POLICY_PROTOCOL_REVISION, > + DisableVariablePolicy, > + ProtocolIsVariablePolicyEnabled, > + RegisterVariablePolicy, > + DumpVariablePolicy, > + LockVariablePolicy > +}; > +EDKII_VAR_CHECK_PROTOCOL mVarCheck =3D { > + VarCheckRegisterSetVariableCheckHandler, > + VarCheckVariablePropertySet, > + VarCheckVariablePropertyGet > +}; > + > +/** > + Some Secure Boot Policy Variable may update following other variable > changes(SecureBoot follows PK change, etc). > + Record their initial State when variable write service is ready. > + > +**/ > +VOID > +EFIAPI > +RecordSecureBootPolicyVarData ( > + VOID > + ); > + > +/** > + Return TRUE if ExitBootServices () has been called. > + > + @retval TRUE If ExitBootServices () has been called. > +**/ > +BOOLEAN > +AtRuntime ( > + VOID > + ) > +{ > + return EfiAtRuntime (); > +} > + > +/** > + Initializes a basic mutual exclusion lock. > + > + This function initializes a basic mutual exclusion lock to the release= d state > + and returns the lock. Each lock provides mutual exclusion access at i= ts task > + priority level. Since there is no preemption or multiprocessor suppor= t in EFI, > + acquiring the lock only consists of raising to the locks TPL. > + If Lock is NULL, then ASSERT(). > + If Priority is not a valid TPL value, then ASSERT(). > + > + @param Lock A pointer to the lock data structure to initialize. > + @param Priority EFI TPL is associated with the lock. > + > + @return The lock. > + > +**/ > +EFI_LOCK * > +InitializeLock ( > + IN OUT EFI_LOCK *Lock, > + IN EFI_TPL Priority > + ) > +{ > + return EfiInitializeLock (Lock, Priority); > +} > + > +/** > + Acquires lock only at boot time. Simply returns at runtime. > + > + This is a temperary function that will be removed when > + EfiAcquireLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiAcquireLock() at boot time, and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to acquire. > + > +**/ > +VOID > +AcquireLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > + if (!AtRuntime ()) { > + EfiAcquireLock (Lock); > + } > +} > + > +/** > + Releases lock only at boot time. Simply returns at runtime. > + > + This is a temperary function which will be removed when > + EfiReleaseLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiReleaseLock() at boot time and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to release. > + > +**/ > +VOID > +ReleaseLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > + if (!AtRuntime ()) { > + EfiReleaseLock (Lock); > + } > +} > + > +/** > + Retrieve the Fault Tolerent Write protocol interface. > + > + @param[out] FtwProtocol The interface of Ftw protocol > + > + @retval EFI_SUCCESS The FTW protocol instance was found and > returned in FtwProtocol. > + @retval EFI_NOT_FOUND The FTW protocol instance was not found. > + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. > + > +**/ > +EFI_STATUS > +GetFtwProtocol ( > + OUT VOID **FtwProtocol > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Locate Fault Tolerent Write protocol > + // > + Status =3D gBS->LocateProtocol ( > + &gEfiFaultTolerantWriteProtocolGuid, > + NULL, > + FtwProtocol > + ); > + return Status; > +} > + > +/** > + Retrieve the FVB protocol interface by HANDLE. > + > + @param[in] FvBlockHandle The handle of FVB protocol that provides > services for > + reading, writing, and erasing the target= block. > + @param[out] FvBlock The interface of FVB protocol > + > + @retval EFI_SUCCESS The interface information for the specif= ied > protocol was returned. > + @retval EFI_UNSUPPORTED The device does not support the FVB prot= ocol. > + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE > or FvBlock is NULL. > + > +**/ > +EFI_STATUS > +GetFvbByHandle ( > + IN EFI_HANDLE FvBlockHandle, > + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock > + ) > +{ > + // > + // To get the FVB protocol interface on the handle > + // > + return gBS->HandleProtocol ( > + FvBlockHandle, > + &gEfiFirmwareVolumeBlockProtocolGuid, > + (VOID **)FvBlock > + ); > +} > + > +/** > + Function returns an array of handles that support the FVB protocol > + in a buffer allocated from pool. > + > + @param[out] NumberHandles The number of handles returned in Buffer= . > + @param[out] Buffer A pointer to the buffer to return the re= quested > + array of handles that support FVB proto= col. > + > + @retval EFI_SUCCESS The array of handles was returned in Buf= fer, and > the number of > + handles in Buffer was returned in Number= Handles. > + @retval EFI_NOT_FOUND No FVB handle was found. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store > the matching results. > + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. > + > +**/ > +EFI_STATUS > +GetFvbCountAndBuffer ( > + OUT UINTN *NumberHandles, > + OUT EFI_HANDLE **Buffer > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Locate all handles of Fvb protocol > + // > + Status =3D gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiFirmwareVolumeBlockProtocolGuid, > + NULL, > + NumberHandles, > + Buffer > + ); > + return Status; > +} > + > +/** > + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. > + > + This is a notification function registered on > EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. > + It convers pointer to new virtual address. > + > + @param Event Event whose notification function is being invoke= d. > + @param Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +VariableClassAddressChangeEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + UINTN Index; > + > + if (mVariableModuleGlobal->FvbInstance !=3D NULL) { > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >GetBlockSize); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >GetPhysicalAddress); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >GetAttributes); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >SetAttributes); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >Read); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >Write); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= - > >EraseBlocks); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->FvbInstance= ); > + } > + > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal- > >PlatformLangCodes); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->LangCodes); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal->PlatformLang)= ; > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal- > >VariableGlobal.NonVolatileVariableBase); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal- > >VariableGlobal.VolatileVariableBase); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal- > >VariableGlobal.HobVariableBase); > + EfiConvertPointer (0x0, (VOID **)&mVariableModuleGlobal); > + EfiConvertPointer (0x0, (VOID **)&mNvVariableCache); > + EfiConvertPointer (0x0, (VOID **)&mNvFvHeaderCache); > + > + if (mAuthContextOut.AddressPointer !=3D NULL) { > + for (Index =3D 0; Index < mAuthContextOut.AddressPointerCount; Index= ++) { > + EfiConvertPointer (0x0, (VOID **)mAuthContextOut.AddressPointer[In= dex]); > + } > + } > + > + if (mVarCheckAddressPointer !=3D NULL) { > + for (Index =3D 0; Index < mVarCheckAddressPointerCount; Index++) { > + EfiConvertPointer (0x0, (VOID **)mVarCheckAddressPointer[Index]); > + } > + } > +} > + > +/** > + Notification function of EVT_GROUP_READY_TO_BOOT event group. > + > + This is a notification function registered on EVT_GROUP_READY_TO_BOOT > event group. > + When the Boot Manager is about to load and execute a boot option, it > reclaims variable > + storage if free size is below the threshold. > + > + @param Event Event whose notification function is being invoke= d. > + @param Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +OnReadyToBoot ( > + EFI_EVENT Event, > + VOID *Context > + ) > +{ > + EFI_STATUS Status; > + > + if (!mEndOfDxe) { > + MorLockInitAtEndOfDxe (); > + > + Status =3D LockVariablePolicy (); > + ASSERT_EFI_ERROR (Status); > + // > + // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUI= D > event is not signaled. > + // > + mEndOfDxe =3D TRUE; > + mVarCheckAddressPointer =3D VarCheckLibInitializeAtEndOfDxe > (&mVarCheckAddressPointerCount); > + // > + // The initialization for variable quota. > + // > + InitializeVariableQuota (); > + } > + > + ReclaimForOS (); > + if (FeaturePcdGet (PcdVariableCollectStatistics)) { > + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { > + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, > gVariableInfo); > + } else { > + gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo); > + } > + } > + > + gBS->CloseEvent (Event); > +} > + > +/** > + Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group. > + > + This is a notification function registered on > EFI_END_OF_DXE_EVENT_GROUP_GUID event group. > + > + @param Event Event whose notification function is being invoke= d. > + @param Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +OnEndOfDxe ( > + EFI_EVENT Event, > + VOID *Context > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "[Variable]END_OF_DXE is signaled\n")); > + MorLockInitAtEndOfDxe (); > + Status =3D LockVariablePolicy (); > + ASSERT_EFI_ERROR (Status); > + mEndOfDxe =3D TRUE; > + mVarCheckAddressPointer =3D VarCheckLibInitializeAtEndOfDxe > (&mVarCheckAddressPointerCount); > + // > + // The initialization for variable quota. > + // > + InitializeVariableQuota (); > + if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) { > + ReclaimForOS (); > + } > + > + gBS->CloseEvent (Event); > +} > + > +/** > + Initializes variable write service for DXE. > + > +**/ > +VOID > +VariableWriteServiceInitializeDxe ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D VariableWriteServiceInitialize (); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. = Status > =3D %r\n", Status)); > + } > + > + // > + // Some Secure Boot Policy Var (SecureBoot, etc) updates following oth= er > + // Secure Boot Policy Variable change. Record their initial value. > + // > + RecordSecureBootPolicyVarData (); > + > + // > + // Install the Variable Write Architectural protocol. > + // > + Status =3D gBS->InstallProtocolInterface ( > + &mHandle, > + &gEfiVariableWriteArchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + Fault Tolerant Write protocol notification event handler. > + > + Non-Volatile variable write may needs FTW protocol to reclaim when > + writting variable. > + > + @param[in] Event Event whose notification function is being invoked= . > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +FtwNotificationEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; > + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; > + EFI_PHYSICAL_ADDRESS NvStorageVariableBase; > + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; > + EFI_PHYSICAL_ADDRESS BaseAddress; > + UINT64 Length; > + EFI_PHYSICAL_ADDRESS VariableStoreBase; > + UINT64 VariableStoreLength; > + UINTN FtwMaxBlockSize; > + UINT32 NvStorageVariableSize; > + UINT64 NvStorageVariableSize64; > + > + // > + // Ensure FTW protocol is installed. > + // > + Status =3D GetFtwProtocol ((VOID **)&FtwProtocol); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + Status =3D GetVariableFlashNvStorageInfo (&NvStorageVariableBase, > &NvStorageVariableSize64); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SafeUint64ToUint32 (NvStorageVariableSize64, > &NvStorageVariableSize); > + // This driver currently assumes the size will be UINT32 so assert the= value is > safe for now. > + ASSERT_EFI_ERROR (Status); > + > + VariableStoreBase =3D NvStorageVariableBase + mNvFvHeaderCache- > >HeaderLength; > + > + Status =3D FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize= ); > + if (!EFI_ERROR (Status)) { > + ASSERT (NvStorageVariableSize <=3D FtwMaxBlockSize); > + } > + > + // > + // Let NonVolatileVariableBase point to flash variable store base dire= ctly after > FTW ready. > + // > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase =3D > VariableStoreBase; > + > + // > + // Find the proper FVB protocol for variable. > + // > + Status =3D GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProto= col); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + mVariableModuleGlobal->FvbInstance =3D FvbProtocol; > + > + // > + // Mark the variable storage region of the FLASH as RUNTIME. > + // > + VariableStoreLength =3D mNvVariableCache->Size; > + BaseAddress =3D VariableStoreBase & (~EFI_PAGE_MASK); > + Length =3D VariableStoreLength + (VariableStoreBase - Bas= eAddress); > + Length =3D (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK= ); > + > + Status =3D gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor)= ; > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_WARN, "Variable driver failed to get flash memory > attribute.\n")); > + } else { > + if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) =3D=3D 0) { > + Status =3D gDS->SetMemorySpaceAttributes ( > + BaseAddress, > + Length, > + GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_WARN, "Variable driver failed to add > EFI_MEMORY_RUNTIME attribute to Flash.\n")); > + } > + } > + } > + > + // > + // Initializes variable write service after FTW was ready. > + // > + VariableWriteServiceInitializeDxe (); > + > + // > + // Close the notify event to avoid install gEfiVariableWriteArchProtoc= olGuid > again. > + // > + gBS->CloseEvent (Event); > +} > + > +/** > + This API function returns whether or not the policy engine is > + currently being enforced. > + > + @param[out] State Pointer to a return value for whether the po= licy > enforcement > + is currently enabled. > + > + @retval EFI_SUCCESS > + @retval Others An error has prevented this command from com= pleting. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtocolIsVariablePolicyEnabled ( > + OUT BOOLEAN *State > + ) > +{ > + *State =3D IsVariablePolicyEnabled (); > + return EFI_SUCCESS; > +} > + > +/** > + Variable Driver main entry point. The Variable driver places the 4 EFI > + runtime services in the EFI System Table and installs arch protocols > + for variable read and write services being available. It also register= s > + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE > event. > + > + @param[in] ImageHandle The firmware allocated handle for the EFI im= age. > + @param[in] SystemTable A pointer to the EFI System Table. > + > + @retval EFI_SUCCESS Variable service successfully initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_EVENT ReadyToBootEvent; > + EFI_EVENT EndOfDxeEvent; > + > + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; > + > + // > + // Initialze protected variable service, if enabled. > + // > + ContextIn.StructSize =3D sizeof (ContextIn); > + ContextIn.StructVersion =3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; > + > + ContextIn.FindVariableSmm =3D NULL; > + ContextIn.GetVariableInfo =3D GetVariableInfo; > + ContextIn.GetNextVariableInfo =3D GetNextVariableInfo; > + ContextIn.UpdateVariableStore =3D VariableExLibUpdateNvVariable; > + ContextIn.UpdateVariable =3D VariableExLibUpdateVariable; > + > + ContextIn.MaxVariableSize =3D (UINT32)GetMaxVariableSize (); > + ContextIn.VariableServiceUser =3D FromSmmModule; > + > + Status =3D ProtectedVariableLibInitialize (&ContextIn); > + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Status =3D VariableCommonInitialize (); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &mHandle, > + &gEdkiiVariableLockProtocolGuid, > + &mVariableLock, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &mHandle, > + &gEdkiiVarCheckProtocolGuid, > + &mVarCheck, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + SystemTable->RuntimeServices->GetVariable =3D > VariableServiceGetVariable; > + SystemTable->RuntimeServices->GetNextVariableName =3D > VariableServiceGetNextVariableName; > + SystemTable->RuntimeServices->SetVariable =3D VariableServiceS= etVariable; > + SystemTable->RuntimeServices->QueryVariableInfo =3D > VariableServiceQueryVariableInfo; > + > + // > + // Now install the Variable Runtime Architectural protocol on a new ha= ndle. > + // > + Status =3D gBS->InstallProtocolInterface ( > + &mHandle, > + &gEfiVariableArchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { > + // > + // Register FtwNotificationEvent () notify function. > + // > + EfiCreateProtocolNotifyEvent ( > + &gEfiFaultTolerantWriteProtocolGuid, > + TPL_CALLBACK, > + FtwNotificationEvent, > + (VOID *)SystemTable, > + &mFtwRegistration > + ); > + } else { > + // > + // Emulated non-volatile variable mode does not depend on FVB and FT= W. > + // > + VariableWriteServiceInitializeDxe (); > + } > + > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + VariableClassAddressChangeEvent, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &mVirtualAddressChangeEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Register the event handling function to reclaim variable for OS usa= ge. > + // > + Status =3D EfiCreateEventReadyToBootEx ( > + TPL_NOTIFY, > + OnReadyToBoot, > + NULL, > + &ReadyToBootEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Register the event handling function to set the End Of DXE flag. > + // > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + OnEndOfDxe, > + NULL, > + &gEfiEndOfDxeEventGroupGuid, > + &EndOfDxeEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // Register and initialize the VariablePolicy engine. > + Status =3D InitVariablePolicyLib (VariableServiceGetVariable); > + ASSERT_EFI_ERROR (Status); > + Status =3D VarCheckRegisterSetVariableCheckHandler (ValidateSetVariabl= e); > + ASSERT_EFI_ERROR (Status); > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &mHandle, > + &gEdkiiVariablePolicyProtocolGuid, > + &mVariablePolicyProtocol, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c > new file mode 100644 > index 000000000000..5904bcbff78a > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableExLib.c > @@ -0,0 +1,417 @@ > +/** @file > + Provides variable driver extended services. > + > +Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +/** > + Finds variable in storage blocks of volatile and non-volatile storage = areas. > + > + This code finds variable in storage blocks of volatile and non-volatil= e storage > areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Variable vendor GUID to be found. > + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO struct= ure > for > + output of the variable found. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty stri= ng, > + while VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibFindVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT AUTH_VARIABLE_INFO *AuthVariableInfo > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK Variable; > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + PROTECTED_VARIABLE_INFO VarInfo; > + > + Status =3D FindVariable ( > + VariableName, > + VendorGuid, > + &Variable, > + &mVariableModuleGlobal->VariableGlobal, > + FALSE > + ); > + if (EFI_ERROR (Status)) { > + AuthVariableInfo->Data =3D NULL; > + AuthVariableInfo->DataSize =3D 0; > + AuthVariableInfo->Attributes =3D 0; > + AuthVariableInfo->PubKeyIndex =3D 0; > + AuthVariableInfo->MonotonicCount =3D 0; > + AuthVariableInfo->TimeStamp =3D NULL; > + return Status; > + } > + > + AuthVariableInfo->NameSize =3D NameSizeOfVariable (Variable.CurrPt= r, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->VariableName =3D GetVariableNamePtr (Variable.CurrPt= r, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->VendorGuid =3D GetVendorGuidPtr (Variable.CurrPtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->DataSize =3D DataSizeOfVariable (Variable.CurrPt= r, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->Data =3D GetVariableDataPtr (Variable.CurrPt= r, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->Attributes =3D Variable.CurrPtr->Attributes; > + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER > *)Variable.CurrPtr; > + AuthVariableInfo->PubKeyIndex =3D AuthVariable->PubKeyIndex; > + AuthVariableInfo->MonotonicCount =3D ReadUnaligned64 (&(AuthVariable= - > >MonotonicCount)); > + AuthVariableInfo->TimeStamp =3D &AuthVariable->TimeStamp; > + } > + > + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header)); > + > + VarInfo.Buffer =3D Variable.CurrPtr; > + VarInfo.PlainData =3D NULL; > + VarInfo.PlainDataSize =3D 0; > + VarInfo.Flags.Auth =3D mVariableModuleGlobal->VariableGlobal.AuthFo= rmat; > + > + // > + // In case the variable is encrypted. > + // > + Status =3D ProtectedVariableLibGetByInfo (&VarInfo); > + if (!EFI_ERROR (Status)) { > + if (VarInfo.PlainData !=3D NULL) { > + AuthVariableInfo->Data =3D VarInfo.PlainData; > + AuthVariableInfo->DataSize =3D VarInfo.PlainDataSize; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Finds next variable in storage blocks of volatile and non-volatile sto= rage areas. > + > + This code finds next variable in storage blocks of volatile and non-vo= latile > storage areas. > + If VariableName is an empty string, then we just return the first > + qualified variable without comparing VariableName and VendorGuid. > + > + @param[in] VariableName Name of the variable to be found. > + @param[in] VendorGuid Variable vendor GUID to be found. > + @param[out] AuthVariableInfo Pointer to AUTH_VARIABLE_INFO struct= ure > for > + output of the next variable. > + > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty stri= ng, > + while VendorGuid is NULL. > + @retval EFI_SUCCESS Variable successfully found. > + @retval EFI_NOT_FOUND Variable not found > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibFindNextVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT AUTH_VARIABLE_INFO *AuthVariableInfo > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_HEADER *VariablePtr; > + AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr; > + VARIABLE_STORE_HEADER > *VariableStoreHeader[VariableStoreTypeMax]; > + PROTECTED_VARIABLE_INFO VarInfo; > + > + VariableStoreHeader[VariableStoreTypeVolatile] =3D > (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.VolatileVariableBase; > + VariableStoreHeader[VariableStoreTypeHob] =3D (VARIABLE_STORE_HEA= DER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + VariableStoreHeader[VariableStoreTypeNv] =3D mNvVariableCache; > + > + Status =3D VariableServiceGetNextVariableInternal ( > + VariableName, > + VendorGuid, > + VariableStoreHeader, > + &VariablePtr, > + mVariableModuleGlobal->VariableGlobal.AuthFormat > + ); > + if (EFI_ERROR (Status)) { > + AuthVariableInfo->VariableName =3D NULL; > + AuthVariableInfo->VendorGuid =3D NULL; > + AuthVariableInfo->Data =3D NULL; > + AuthVariableInfo->DataSize =3D 0; > + AuthVariableInfo->Attributes =3D 0; > + AuthVariableInfo->PubKeyIndex =3D 0; > + AuthVariableInfo->MonotonicCount =3D 0; > + AuthVariableInfo->TimeStamp =3D NULL; > + return Status; > + } > + > + AuthVariableInfo->NameSize =3D NameSizeOfVariable (VariablePtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->VariableName =3D GetVariableNamePtr (VariablePtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->VendorGuid =3D GetVendorGuidPtr (VariablePtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->DataSize =3D DataSizeOfVariable (VariablePtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->Data =3D GetVariableDataPtr (VariablePtr, > mVariableModuleGlobal->VariableGlobal.AuthFormat); > + AuthVariableInfo->Attributes =3D VariablePtr->Attributes; > + if (mVariableModuleGlobal->VariableGlobal.AuthFormat) { > + AuthVariablePtr =3D (AUTHENTICATED_VARIABLE_HEADER > *)VariablePtr; > + AuthVariableInfo->PubKeyIndex =3D AuthVariablePtr->PubKeyIndex; > + AuthVariableInfo->MonotonicCount =3D ReadUnaligned64 (&(AuthVariable= Ptr- > >MonotonicCount)); > + AuthVariableInfo->TimeStamp =3D &AuthVariablePtr->TimeStamp; > + } > + > + CopyMem (&VarInfo.Header, AuthVariableInfo, sizeof (VarInfo.Header)); > + > + VarInfo.Buffer =3D VariablePtr; > + VarInfo.PlainData =3D NULL; > + VarInfo.PlainDataSize =3D 0; > + > + Status =3D ProtectedVariableLibGetByInfo (&VarInfo); > + if (!EFI_ERROR (Status)) { > + if (VarInfo.PlainData !=3D NULL) { > + AuthVariableInfo->Data =3D VarInfo.PlainData; > + AuthVariableInfo->DataSize =3D VarInfo.PlainDataSize; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Update the variable region with Variable information. > + > + @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure= for > + input of the variable. > + > + @retval EFI_SUCCESS The update operation is success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_WRITE_PROTECTED Variable is write-protected. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibUpdateVariable ( > + IN AUTH_VARIABLE_INFO *AuthVariableInfo > + ) > +{ > + VARIABLE_POINTER_TRACK Variable; > + > + FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo- > >VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); > + return UpdateVariable ( > + AuthVariableInfo->VariableName, > + AuthVariableInfo->VendorGuid, > + AuthVariableInfo->Data, > + AuthVariableInfo->DataSize, > + AuthVariableInfo->Attributes, > + AuthVariableInfo->PubKeyIndex, > + AuthVariableInfo->MonotonicCount, > + &Variable, > + AuthVariableInfo->TimeStamp > + ); > +} > + > +/** > + Get scratch buffer. > + > + @param[in, out] ScratchBufferSize Scratch buffer size. If input size i= s greater > than > + the maximum supported buffer size, t= his value contains > + the maximum supported buffer size as= output. > + @param[out] ScratchBuffer Pointer to scratch buffer address. > + > + @retval EFI_SUCCESS Get scratch buffer successfully. > + @retval EFI_UNSUPPORTED If input size is greater than the maximum > supported buffer size. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibGetScratchBuffer ( > + IN OUT UINTN *ScratchBufferSize, > + OUT VOID **ScratchBuffer > + ) > +{ > + UINTN MaxBufferSize; > + > + MaxBufferSize =3D mVariableModuleGlobal->ScratchBufferSize; > + if (*ScratchBufferSize > MaxBufferSize) { > + *ScratchBufferSize =3D MaxBufferSize; > + return EFI_UNSUPPORTED; > + } > + > + *ScratchBuffer =3D GetEndPointer ((VARIABLE_STORE_HEADER > *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)); > + return EFI_SUCCESS; > +} > + > +/** > + This function is to check if the remaining variable space is enough to= set > + all Variables from argument list successfully. The purpose of the chec= k > + is to keep the consistency of the Variables to be in variable storage. > + > + Note: Variables are assumed to be in same storage. > + The set sequence of Variables will be same with the sequence of Variab= leEntry > from argument list, > + so follow the argument sequence to check the Variables. > + > + @param[in] Attributes Variable attributes for Variable entries= . > + @param ... The variable argument list with type > VARIABLE_ENTRY_CONSISTENCY *. > + A NULL terminates the list. The Variable= Size of > + VARIABLE_ENTRY_CONSISTENCY is the variab= le data size as > input. > + It will be changed to variable total siz= e as output. > + > + @retval TRUE Have enough variable space to set the Va= riables > successfully. > + @retval FALSE No enough variable space to set the Vari= ables > successfully. > + > +**/ > +BOOLEAN > +EFIAPI > +VariableExLibCheckRemainingSpaceForConsistency ( > + IN UINT32 Attributes, > + ... > + ) > +{ > + VA_LIST Marker; > + BOOLEAN Return; > + > + VA_START (Marker, Attributes); > + > + Return =3D CheckRemainingSpaceForConsistencyInternal (Attributes, Mark= er); > + > + VA_END (Marker); > + > + return Return; > +} > + > +/** > + Return TRUE if at OS runtime. > + > + @retval TRUE If at OS runtime. > + @retval FALSE If at boot time. > + > +**/ > +BOOLEAN > +EFIAPI > +VariableExLibAtRuntime ( > + VOID > + ) > +{ > + return AtRuntime (); > +} > + > +/** > + Update partial data of a variable on NV storage and/or cached copy. > + > + @param[in] VariableInfo Pointer to a variable with detailed informat= ion. > + @param[in] Offset Offset to write from. > + @param[in] Size Size of data Buffer to update. > + @param[in] Buffer Pointer to data buffer to update. > + > + @retval EFI_SUCCESS The variable data was updated successf= ully. > + @retval EFI_UNSUPPORTED If this function is called directly in= runtime. > + @retval EFI_INVALID_PARAMETER If VariableInfo, Buffer or Size are no= t > valid. > + @retval Others Failed to update NV storage or variabl= e cache. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableExLibUpdateNvVariable ( > + IN PROTECTED_VARIABLE_INFO *VariableInfo, > + IN UINTN Offset, > + IN UINT32 Size, > + IN UINT8 *Buffer > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_GLOBAL *Global; > + VARIABLE_RUNTIME_CACHE *CacheInstance; > + VARIABLE_HEADER *VariableCache; > + > + if ((mVariableModuleGlobal =3D=3D NULL) || (mNvVariableCache =3D=3D NU= LL)) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Flush the cache to store. > + // > + if (Size =3D=3D (UINT32)-1) { > + Status =3D FtwVariableSpace ( > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariable= Base, > + mNvVariableCache > + ); > + if ( !EFI_ERROR (Status) > + && (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0)= ) > + { > + FlushHobVariableToFlash (NULL, NULL); > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase !=3D 0) = { > + FreePool ((VOID *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.HobVariableBase); > + mVariableModuleGlobal->VariableGlobal.HobVariableBase =3D 0; > + } > + } > + > + return Status; > + } > + > + if ( (VariableInfo =3D=3D NULL) > + || (VariableInfo->StoreIndex =3D=3D VAR_INDEX_INVALID) > + || (Buffer =3D=3D NULL) > + || (Size =3D=3D 0)) > + { > + ASSERT (VariableInfo !=3D NULL); > + ASSERT (VariableInfo->StoreIndex !=3D VAR_INDEX_INVALID); > + ASSERT (Buffer !=3D NULL); > + ASSERT (Size !=3D 0); > + return EFI_INVALID_PARAMETER; > + } > + > + Global =3D &mVariableModuleGlobal->VariableGlobal; > + > + VariableCache =3D (VARIABLE_HEADER *)((UINTN)mNvVariableCache + > (UINTN)VariableInfo->StoreIndex); > + > + ASSERT ( > + StrCmp ( > + VariableInfo->Header.VariableName, > + GetVariableNamePtr (VariableCache, Global->AuthFormat) > + ) =3D=3D 0 > + ); > + ASSERT ( > + CompareGuid ( > + VariableInfo->Header.VendorGuid, > + GetVendorGuidPtr (VariableCache, Global->AuthFormat) > + ) > + ); > + > + // > + // Forcibly update part data of flash copy of the variable ... > + // > + Status =3D UpdateVariableStore ( > + Global, > + FALSE, > + FALSE, > + mVariableModuleGlobal->FvbInstance, > + (UINTN)(Global->NonVolatileVariableBase + VariableInfo->St= oreIndex + > Offset), > + Size, > + Buffer > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // > + // ... as well as the local cached copy. > + // > + CopyMem ((VOID *)((UINTN)VariableCache + Offset), Buffer, Size); > + > + // > + // Sync remote cached copy. > + // > + CacheInstance =3D &Global- > >VariableRuntimeCacheContext.VariableRuntimeNvCache; > + if (CacheInstance->Store !=3D NULL) { > + Status =3D SynchronizeRuntimeVariableCache ( > + CacheInstance, > + (UINTN)VariableInfo->StoreIndex + Offset, > + Size > + ); > + ASSERT_EFI_ERROR (Status); > + } > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ > estToLock.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ > estToLock.c > new file mode 100644 > index 000000000000..d849ee9ce292 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableLockRequ > estToLock.c > @@ -0,0 +1,96 @@ > +/** @file > + Temporary location of the RequestToLock shim code while projects > + are moved to VariablePolicy. Should be removed when deprecated. > + > + Copyright (c) Microsoft Corporation. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +/** > + DEPRECATED. THIS IS ONLY HERE AS A CONVENIENCE WHILE PORTING. > + Mark a variable that will become read-only after leaving the DXE phase= of > + execution. Write request coming from SMM environment through > + EFI_SMM_VARIABLE_PROTOCOL is allowed. > + > + @param[in] This The VARIABLE_LOCK_PROTOCOL instance. > + @param[in] VariableName A pointer to the variable name that will be m= ade > + read-only subsequently. > + @param[in] VendorGuid A pointer to the vendor GUID that will be mad= e > + read-only subsequently. > + > + @retval EFI_SUCCESS The variable specified by the VariableNa= me and > + the VendorGuid was marked as pending to = be > + read-only. > + @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL. > + Or VariableName is an empty string. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > + EFI_EVENT_GROUP_READY_TO_BOOT has alread= y been > + signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the > lock > + request. > +**/ > +EFI_STATUS > +EFIAPI > +VariableLockRequestToLock ( > + IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POLICY_ENTRY *NewPolicy; > + > + DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! %a() will go away > soon!\n", __FUNCTION__)); > + DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Please move to use > Variable Policy!\n")); > + DEBUG ((DEBUG_WARN, "!!! DEPRECATED INTERFACE !!! Variable: %g %s\n", > VendorGuid, VariableName)); > + > + NewPolicy =3D NULL; > + Status =3D CreateBasicVariablePolicy ( > + VendorGuid, > + VariableName, > + VARIABLE_POLICY_NO_MIN_SIZE, > + VARIABLE_POLICY_NO_MAX_SIZE, > + VARIABLE_POLICY_NO_MUST_ATTR, > + VARIABLE_POLICY_NO_CANT_ATTR, > + VARIABLE_POLICY_TYPE_LOCK_NOW, > + &NewPolicy > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D RegisterVariablePolicy (NewPolicy); > + > + // > + // If the error returned is EFI_ALREADY_STARTED, we need to check th= e > + // current database for the variable and see whether it's locked. If= it's > + // locked, we're still fine, but also generate a DEBUG_WARN message = so the > + // duplicate lock can be removed. > + // > + if (Status =3D=3D EFI_ALREADY_STARTED) { > + Status =3D ValidateSetVariable (VariableName, VendorGuid, 0, 0, NU= LL); > + if (Status =3D=3D EFI_WRITE_PROTECTED) { > + DEBUG ((DEBUG_WARN, " Variable: %g %s is already locked!\n", > VendorGuid, VariableName)); > + Status =3D EFI_SUCCESS; > + } else { > + DEBUG ((DEBUG_ERROR, " Variable: %g %s can not be locked!\n", > VendorGuid, VariableName)); > + Status =3D EFI_ACCESS_DENIED; > + } > + } > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", > __FUNCTION__, VariableName, Status)); > + } > + > + if (NewPolicy !=3D NULL) { > + FreePool (NewPolicy); > + } > + > + return Status; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.c > new file mode 100644 > index 000000000000..32dd9901b260 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableNonVolat > ile.c > @@ -0,0 +1,537 @@ > +/** @file > + Common variable non-volatile store routines. > + > +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "VariableNonVolatile.h" > +#include "VariableParsing.h" > + > +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; > + > +/** > + Get non-volatile maximum variable size. > + > + @return Non-volatile maximum variable size. > + > +**/ > +UINTN > +GetNonVolatileMaxVariableSize ( > + VOID > + ) > +{ > + if (PcdGet32 (PcdHwErrStorageSize) !=3D 0) { > + return MAX ( > + MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 > (PcdMaxAuthVariableSize)), > + PcdGet32 (PcdMaxHardwareErrorVariableSize) > + ); > + } else { > + return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 > (PcdMaxAuthVariableSize)); > + } > +} > + > +/** > + Init emulated non-volatile variable store. > + > + @param[out] VariableStoreBase Output pointer to emulated non-volatile > variable store base. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + > +**/ > +EFI_STATUS > +InitEmuNonVolatileVariableStore ( > + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase > + ) > +{ > + VARIABLE_STORE_HEADER *VariableStore; > + UINT32 VariableStoreLength; > + BOOLEAN FullyInitializeStore; > + UINT32 HwErrStorageSize; > + > + FullyInitializeStore =3D TRUE; > + > + VariableStoreLength =3D PcdGet32 (PcdVariableStoreSize); > + ASSERT (sizeof (VARIABLE_STORE_HEADER) <=3D VariableStoreLength); > + > + // > + // Allocate memory for variable store. > + // > + if (PcdGet64 (PcdEmuVariableNvStoreReserved) =3D=3D 0) { > + VariableStore =3D (VARIABLE_STORE_HEADER *)AllocateRuntimePool > (VariableStoreLength); > + if (VariableStore =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + // > + // A memory location has been reserved for the NV variable store. C= ertain > + // platforms may be able to preserve a memory range across system re= sets, > + // thereby providing better NV variable emulation. > + // > + VariableStore =3D > + (VARIABLE_STORE_HEADER *)(VOID *)(UINTN) > + PcdGet64 (PcdEmuVariableNvStoreReserved); > + if ((VariableStore->Size =3D=3D VariableStoreLength) && > + (CompareGuid (&VariableStore->Signature, > &gEfiAuthenticatedVariableGuid) || > + CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) && > + (VariableStore->Format =3D=3D VARIABLE_STORE_FORMATTED) && > + (VariableStore->State =3D=3D VARIABLE_STORE_HEALTHY)) > + { > + DEBUG (( > + DEBUG_INFO, > + "Variable Store reserved at %p appears to be valid\n", > + VariableStore > + )); > + FullyInitializeStore =3D FALSE; > + } > + } > + > + if (FullyInitializeStore) { > + SetMem (VariableStore, VariableStoreLength, 0xff); > + // > + // Use gEfiAuthenticatedVariableGuid for potential auth variable sup= port. > + // > + CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid)= ; > + VariableStore->Size =3D VariableStoreLength; > + VariableStore->Format =3D VARIABLE_STORE_FORMATTED; > + VariableStore->State =3D VARIABLE_STORE_HEALTHY; > + VariableStore->Reserved =3D 0; > + VariableStore->Reserved1 =3D 0; > + } > + > + *VariableStoreBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore; > + > + HwErrStorageSize =3D PcdGet32 (PcdHwErrStorageSize); > + > + // > + // Note that in EdkII variable driver implementation, Hardware Error R= ecord > type variable > + // is stored with common variable in the same NV region. So the platfo= rm > integrator should > + // ensure that the value of PcdHwErrStorageSize is less than the value= of > + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). > + // > + ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof > (VARIABLE_STORE_HEADER))); > + > + mVariableModuleGlobal->CommonVariableSpace =3D > ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - > HwErrStorageSize); > + mVariableModuleGlobal->CommonMaxUserVariableSpace =3D > mVariableModuleGlobal->CommonVariableSpace; > + mVariableModuleGlobal->CommonRuntimeVariableSpace =3D > mVariableModuleGlobal->CommonVariableSpace; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Create a dummy variable used to fill the gap in NV variable storage ca= used by > + the invalid variables found in HMAC verification phase. > + > + @param[out] Variable Variable buffer. > + @param[in] Name Variable Name. > + @param[in] Guid Vendor GUID of the variable. > + @param[in] Size Whole size of the variable requested. > + @param[in] AuthFlag Variable format flag. > + > +**/ > +STATIC > +VOID > +CreateDummyVariable ( > + OUT VARIABLE_HEADER *Variable, > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + IN UINT32 Size, > + IN BOOLEAN AuthFlag > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + ASSERT (Variable !=3D NULL); > + > + if (Name =3D=3D NULL) { > + Name =3D L"Dummy"; > + } > + > + if (AuthFlag) { > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + > + AuthVariable->StartId =3D VARIABLE_DATA; > + AuthVariable->State =3D VAR_ADDED & VAR_DELETED; > + AuthVariable->Attributes =3D EFI_VARIABLE_NON_VOLATILE; > + AuthVariable->NameSize =3D (UINT32)StrSize (Name); > + AuthVariable->DataSize =3D Size - sizeof > (AUTHENTICATED_VARIABLE_HEADER) > + - AuthVariable->NameSize; > + if (Guid !=3D NULL) { > + CopyMem ((VOID *)&AuthVariable->VendorGuid, (VOID *)Guid, sizeof > (EFI_GUID)); > + } > + > + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, > AuthVariable->NameSize); > + } else { > + Variable->StartId =3D VARIABLE_DATA; > + Variable->State =3D VAR_ADDED & VAR_DELETED; > + Variable->Attributes =3D EFI_VARIABLE_NON_VOLATILE; > + Variable->NameSize =3D (UINT32)StrSize (Name); > + Variable->DataSize =3D Size - sizeof (VARIABLE_HEADER) - Variable- > >NameSize; > + if (Guid !=3D NULL) { > + CopyMem ((VOID *)&Variable->VendorGuid, (VOID *)Guid, sizeof > (EFI_GUID)); > + } > + > + CopyMem (GetVariableNamePtr (Variable, AuthFlag), (VOID *)Name, > Variable->NameSize); > + } > +} > + > +/** > + > + Init protected variable store. > + > + @param[in, out] VariableStore Pointer to real protected variable sto= re base. > + > +**/ > +EFI_STATUS > +InitProtectedVariableStore ( > + IN OUT VARIABLE_STORE_HEADER *VariableStore > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + UINTN Size; > + UINTN Index; > + BOOLEAN AuthFlag; > + EFI_PHYSICAL_ADDRESS NextVariableStore; > + EFI_PHYSICAL_ADDRESS *VarList; > + UINTN NumVars; > + UINTN CurrVar; > + > + SetMem ( > + (UINT8 *)VariableStore + sizeof (VARIABLE_STORE_HEADER), > + VariableStore->Size - sizeof (VARIABLE_STORE_HEADER), > + 0xFF > + ); > + Index =3D sizeof (VARIABLE_STORE_HEADER); > + > + VarList =3D NULL; > + NumVars =3D 0; > + ProtectedVariableLibGetSortedList (&VarList, &NumVars); > + > + // > + // Search variable in the order of StoreIndex > + // > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + > + for (CurrVar =3D 0; CurrVar < NumVars; CurrVar++) { > + VarInfo.Buffer =3D NULL; > + VarInfo.StoreIndex =3D VarList[CurrVar]; > + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { > + break; > + } > + > + Status =3D ProtectedVariableLibFind (&VarInfo); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + ASSERT (VarInfo.Buffer !=3D NULL); > + > + AuthFlag =3D VarInfo.Flags.Auth; > + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { > + continue; > + } else { > + ASSERT (VarInfo.StoreIndex =3D=3D HEADER_ALIGN (VarInfo.StoreIndex= )); > + ASSERT (VarInfo.StoreIndex < (VariableStore->Size - sizeof > (VARIABLE_STORE_HEADER))); > + ASSERT ((VariableStore->Size - VarInfo.StoreIndex) > GetVariableHe= aderSize > (AuthFlag)); > + } > + > + // > + // Fill gap caused by invalid variable. > + // > + if (VarInfo.StoreIndex > Index) { > + Size =3D (UINTN)VarInfo.StoreIndex - Index; > + CreateDummyVariable ( > + (VARIABLE_HEADER *)((UINT8 *)VariableStore + Index), > + NULL, > + NULL, > + (UINT32)Size, > + AuthFlag > + ); > + Index +=3D Size; > + } > + > + Size =3D (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag) > + - (UINTN)VarInfo.Buffer; > + CopyMem ((UINT8 *)VariableStore + VarInfo.StoreIndex, VarInfo.Buffer= , > Size); > + > + Index +=3D Size; > + Index =3D HEADER_ALIGN (Index); > + > + NextVariableStore =3D (EFI_PHYSICAL_ADDRESS)((UINTN)VariableStore + > VarInfo.StoreIndex + Size); > + } > + > + // > + // Search variable in the order of StoreIndex > + // > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + for ( ; CurrVar < NumVars; CurrVar++) { > + VarInfo.Buffer =3D NULL; > + VarInfo.StoreIndex =3D VarList[CurrVar]; > + Status =3D ProtectedVariableLibFind (&VarInfo); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + ASSERT (VarInfo.Buffer !=3D NULL); > + > + AuthFlag =3D VarInfo.Flags.Auth; > + if (VarInfo.StoreIndex =3D=3D VAR_INDEX_INVALID) { > + Size =3D (UINTN)GetNextVariablePtr (VarInfo.Buffer, AuthFlag) > + - (UINTN)VarInfo.Buffer; > + CopyMem ((VOID *)(UINTN)NextVariableStore, VarInfo.Buffer, Size); > + Status =3D ProtectedVariableLibRefresh (VarInfo.Buffer,= 0, > NextVariableStore - (UINTN)VariableStore, FALSE); > + NextVariableStore =3D NextVariableStore + Size; > + } > + } > + > + if (Status =3D=3D EFI_UNSUPPORTED) { > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Init real non-volatile variable store. > + > + @param[out] VariableStoreBase Output pointer to real non-volatile vari= able > store base. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for > Variable Store is corrupted. > + > +**/ > +EFI_STATUS > +InitRealNonVolatileVariableStore ( > + OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase > + ) > +{ > + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; > + VARIABLE_STORE_HEADER *VariableStore; > + UINT32 VariableStoreLength; > + EFI_HOB_GUID_TYPE *GuidHob; > + EFI_PHYSICAL_ADDRESS NvStorageBase; > + UINT8 *NvStorageData; > + UINT32 NvStorageSize; > + UINT64 NvStorageSize64; > + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; > + UINT32 BackUpOffset; > + UINT32 BackUpSize; > + UINT32 HwErrStorageSize; > + UINT32 MaxUserNvVariableSpaceSize; > + UINT32 BoottimeReservedNvVariableSpaceS= ize; > + EFI_STATUS Status; > + VOID *FtwProtocol; > + > + mVariableModuleGlobal->FvbInstance =3D NULL; > + > + Status =3D GetVariableFlashNvStorageInfo (&NvStorageBase, > &NvStorageSize64); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize); > + // This driver currently assumes the size will be UINT32 so assert the= value is > safe for now. > + ASSERT_EFI_ERROR (Status); > + > + ASSERT (NvStorageBase !=3D 0); > + > + // > + // Allocate runtime memory used for a memory copy of the FLASH region. > + // Keep the memory and the FLASH in sync as updates occur. > + // > + NvStorageData =3D AllocateRuntimeZeroPool (NvStorageSize); > + if (NvStorageData =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Copy NV storage data to the memory buffer. > + // > + CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize); > + > + Status =3D GetFtwProtocol ((VOID **)&FtwProtocol); > + // > + // If FTW protocol has been installed, no need to check FTW last write= data > hob. > + // > + if (EFI_ERROR (Status)) { > + // > + // Check the FTW last write data hob. > + // > + GuidHob =3D GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); > + if (GuidHob !=3D NULL) { > + FtwLastWriteData =3D (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA > *)GET_GUID_HOB_DATA (GuidHob); > + if (FtwLastWriteData->TargetAddress =3D=3D NvStorageBase) { > + DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare = block: > 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress)); > + // > + // Copy the backed up NV storage data to the memory buffer from = spare > block. > + // > + CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData- > >SpareAddress), NvStorageSize); > + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && > + (FtwLastWriteData->TargetAddress < (NvStorageBase + > NvStorageSize))) > + { > + // > + // Flash NV storage from the Offset is backed up in spare block. > + // > + BackUpOffset =3D (UINT32)(FtwLastWriteData->TargetAddress - > NvStorageBase); > + BackUpSize =3D NvStorageSize - BackUpOffset; > + DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offs= et: %x > is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteDa= ta- > >SpareAddress)); > + // > + // Copy the partial backed up NV storage data to the memory buff= er from > spare block. > + // > + CopyMem (NvStorageData + BackUpOffset, (UINT8 > *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize); > + } > + } > + } > + > + FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData; > + > + // > + // Check if the Firmware Volume is not corrupted > + // > + if ((FvHeader->Signature !=3D EFI_FVH_SIGNATURE) || (!CompareGuid > (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { > + FreePool (NvStorageData); > + DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is > corrupted\n")); > + return EFI_VOLUME_CORRUPTED; > + } > + > + VariableStore =3D (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + > FvHeader->HeaderLength); > + VariableStoreLength =3D NvStorageSize - FvHeader->HeaderLength; > + ASSERT (sizeof (VARIABLE_STORE_HEADER) <=3D VariableStoreLength); > + ASSERT (VariableStore->Size =3D=3D VariableStoreLength); > + > + // > + // Check if the Variable Store header is not corrupted > + // > + if (GetVariableStoreStatus (VariableStore) !=3D EfiValid) { > + FreePool (NvStorageData); > + DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n")); > + return EFI_VOLUME_CORRUPTED; > + } > + > + // > + // Overwrite the store with verified copy of protected variables, if e= nabled. > + // > + Status =3D InitProtectedVariableStore (VariableStore); > + if ((Status !=3D EFI_SUCCESS) && (Status !=3D EFI_UNSUPPORTED)) { > + FreePool (NvStorageData); > + DEBUG ((DEBUG_ERROR, "Variable integrity might have been > compromised\n")); > + return Status; > + } > + > + mNvFvHeaderCache =3D FvHeader; > + > + *VariableStoreBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore; > + > + HwErrStorageSize =3D PcdGet32 (PcdHwErrStorageSize)= ; > + MaxUserNvVariableSpaceSize =3D PcdGet32 > (PcdMaxUserNvVariableSpaceSize); > + BoottimeReservedNvVariableSpaceSize =3D PcdGet32 > (PcdBoottimeReservedNvVariableSpaceSize); > + > + // > + // Note that in EdkII variable driver implementation, Hardware Error R= ecord > type variable > + // is stored with common variable in the same NV region. So the platfo= rm > integrator should > + // ensure that the value of PcdHwErrStorageSize is less than the value= of > + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). > + // > + ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof > (VARIABLE_STORE_HEADER))); > + // > + // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than= the > value of > + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 > (PcdHwErrStorageSize). > + // > + ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof > (VARIABLE_STORE_HEADER) - HwErrStorageSize)); > + // > + // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is = less > than the value of > + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 > (PcdHwErrStorageSize). > + // > + ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - > sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize)); > + > + mVariableModuleGlobal->CommonVariableSpace =3D > ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - > HwErrStorageSize); > + mVariableModuleGlobal->CommonMaxUserVariableSpace =3D > ((MaxUserNvVariableSpaceSize !=3D 0) ? MaxUserNvVariableSpaceSize : > mVariableModuleGlobal->CommonVariableSpace); > + mVariableModuleGlobal->CommonRuntimeVariableSpace =3D > mVariableModuleGlobal->CommonVariableSpace - > BoottimeReservedNvVariableSpaceSize; > + > + DEBUG (( > + DEBUG_INFO, > + "Variable driver common space: 0x%x 0x%x 0x%x\n", > + mVariableModuleGlobal->CommonVariableSpace, > + mVariableModuleGlobal->CommonMaxUserVariableSpace, > + mVariableModuleGlobal->CommonRuntimeVariableSpace > + )); > + > + // > + // The max NV variable size should be < (VariableStoreLength - sizeof > (VARIABLE_STORE_HEADER)). > + // > + ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - size= of > (VARIABLE_STORE_HEADER))); > + > + return EFI_SUCCESS; > +} > + > +/** > + Init non-volatile variable store. > + > + @retval EFI_SUCCESS Function successfully executed. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. > + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for > Variable Store is corrupted. > + > +**/ > +EFI_STATUS > +InitNonVolatileVariableStore ( > + VOID > + ) > +{ > + VARIABLE_HEADER *Variable; > + VARIABLE_HEADER *NextVariable; > + EFI_PHYSICAL_ADDRESS VariableStoreBase; > + UINTN VariableSize; > + EFI_STATUS Status; > + > + if (PcdGetBool (PcdEmuVariableNvModeEnable)) { > + Status =3D InitEmuNonVolatileVariableStore (&VariableStoreBase); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + mVariableModuleGlobal->VariableGlobal.EmuNvMode =3D TRUE; > + DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volat= ile > variable mode!\n")); > + } else { > + Status =3D InitRealNonVolatileVariableStore (&VariableStoreBase); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + mVariableModuleGlobal->VariableGlobal.EmuNvMode =3D FALSE; > + } > + > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase =3D > VariableStoreBase; > + mNvVariableCache =3D (VAR= IABLE_STORE_HEADER > *)(UINTN)VariableStoreBase; > + mVariableModuleGlobal->VariableGlobal.AuthFormat =3D > (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, > &gEfiAuthenticatedVariableGuid)); > + > + mVariableModuleGlobal->MaxVariableSize =3D PcdGet32 > (PcdMaxVariableSize); > + mVariableModuleGlobal->MaxAuthVariableSize =3D ((PcdGet32 > (PcdMaxAuthVariableSize) !=3D 0) ? PcdGet32 (PcdMaxAuthVariableSize) : > mVariableModuleGlobal->MaxVariableSize); > + > + // > + // Parse non-volatile variable data and get last variable offset. > + // > + Variable =3D GetStartPointer (mNvVariableCache); > + while (IsValidVariableHeader ( > + Variable, > + GetEndPointer (mNvVariableCache), > + mVariableModuleGlobal->VariableGlobal.AuthFormat > + )) > + { > + NextVariable =3D GetNextVariablePtr (Variable, mVariableModuleGlobal= - > >VariableGlobal.AuthFormat); > + VariableSize =3D (UINTN)NextVariable - (UINTN)Variable; > + if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_HARDWARE_ERROR_RECORD)) =3D=3D > (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) > { > + mVariableModuleGlobal->HwErrVariableTotalSize +=3D VariableSize; > + } else { > + mVariableModuleGlobal->CommonVariableTotalSize +=3D VariableSize; > + } > + > + Variable =3D NextVariable; > + } > + > + mVariableModuleGlobal->NonVolatileLastVariableOffset =3D (UINTN)Variab= le - > (UINTN)mNvVariableCache; > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c > new file mode 100644 > index 000000000000..be3f59341c1e > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableParsing.c > @@ -0,0 +1,1110 @@ > +/** @file > + Functions in this module are associated with variable parsing operatio= ns and > + are intended to be usable across variable driver source files. > + > +Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > +#include "VariableParsing.h" > + > +/** > + > + This code checks if variable header is valid or not. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] VariableStoreEnd Pointer to the Variable Store End. > + @param[in] AuthFormat TRUE indicates authenticated variables a= re used. > + FALSE indicates authenticated variables = are not used. > + > + @retval TRUE Variable header is valid. > + @retval FALSE Variable header is not valid. > + > +**/ > +BOOLEAN > +IsValidVariableHeader ( > + IN VARIABLE_HEADER *Variable, > + IN VARIABLE_HEADER *VariableStoreEnd, > + IN BOOLEAN AuthFormat > + ) > +{ > + if ( (Variable =3D=3D NULL) > + || (((UINTN)Variable + GetVariableHeaderSize (AuthFormat)) >=3D > (UINTN)VariableStoreEnd) > + || (Variable->StartId !=3D VARIABLE_DATA)) > + { > + // > + // Variable is NULL or has reached the end of variable store, > + // or the StartId is not correct. > + // > + return FALSE; > + } > + > + return TRUE; > +} > + > +/** > + > + This code gets the current status of Variable Store. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @retval EfiRaw Variable store status is raw. > + @retval EfiValid Variable store status is valid. > + @retval EfiInvalid Variable store status is invalid. > + > +**/ > +VARIABLE_STORE_STATUS > +GetVariableStoreStatus ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ) > +{ > + if ((CompareGuid (&VarStoreHeader->Signature, > &gEfiAuthenticatedVariableGuid) || > + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && > + (VarStoreHeader->Format =3D=3D VARIABLE_STORE_FORMATTED) && > + (VarStoreHeader->State =3D=3D VARIABLE_STORE_HEALTHY) > + ) > + { > + return EfiValid; > + } else if ((((UINT32 *)(&VarStoreHeader->Signature))[0] =3D=3D 0xfffff= fff) && > + (((UINT32 *)(&VarStoreHeader->Signature))[1] =3D=3D 0xfffff= fff) && > + (((UINT32 *)(&VarStoreHeader->Signature))[2] =3D=3D 0xfffff= fff) && > + (((UINT32 *)(&VarStoreHeader->Signature))[3] =3D=3D 0xfffff= fff) && > + (VarStoreHeader->Size =3D=3D 0xffffffff) && > + (VarStoreHeader->Format =3D=3D 0xff) && > + (VarStoreHeader->State =3D=3D 0xff) > + ) > + { > + return EfiRaw; > + } else { > + return EfiInvalid; > + } > +} > + > +/** > + This code gets the size of variable header. > + > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return Size of variable header in bytes in type UINTN. > + > +**/ > +UINTN > +GetVariableHeaderSize ( > + IN BOOLEAN AuthFormat > + ) > +{ > + UINTN Value; > + > + if (AuthFormat) { > + Value =3D sizeof (AUTHENTICATED_VARIABLE_HEADER); > + } else { > + Value =3D sizeof (VARIABLE_HEADER); > + } > + > + return Value; > +} > + > +/** > + > + This code gets the size of name of variable. > + > + @param[in] Variable Pointer to the variable header. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return UINTN Size of variable in bytes. > + > +**/ > +UINTN > +NameSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + if (AuthFormat) { > + if ((AuthVariable->State =3D=3D (UINT8)(-1)) || > + (AuthVariable->DataSize =3D=3D (UINT32)(-1)) || > + (AuthVariable->NameSize =3D=3D (UINT32)(-1)) || > + (AuthVariable->Attributes =3D=3D (UINT32)(-1))) > + { > + return 0; > + } > + > + return (UINTN)AuthVariable->NameSize; > + } else { > + if ((Variable->State =3D=3D (UINT8)(-1)) || > + (Variable->DataSize =3D=3D (UINT32)(-1)) || > + (Variable->NameSize =3D=3D (UINT32)(-1)) || > + (Variable->Attributes =3D=3D (UINT32)(-1))) > + { > + return 0; > + } > + > + return (UINTN)Variable->NameSize; > + } > +} > + > +/** > + This code sets the size of name of variable. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] NameSize Name size to set. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > +**/ > +VOID > +SetNameSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN UINTN NameSize, > + IN BOOLEAN AuthFormat > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + if (AuthFormat) { > + AuthVariable->NameSize =3D (UINT32)NameSize; > + } else { > + Variable->NameSize =3D (UINT32)NameSize; > + } > +} > + > +/** > + > + This code gets the size of variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are u= sed. > + FALSE indicates authenticated variables are = not used. > + > + @return Size of variable in bytes. > + > +**/ > +UINTN > +DataSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + if (AuthFormat) { > + if ((AuthVariable->State =3D=3D (UINT8)(-1)) || > + (AuthVariable->DataSize =3D=3D (UINT32)(-1)) || > + (AuthVariable->NameSize =3D=3D (UINT32)(-1)) || > + (AuthVariable->Attributes =3D=3D (UINT32)(-1))) > + { > + return 0; > + } > + > + return (UINTN)AuthVariable->DataSize; > + } else { > + if ((Variable->State =3D=3D (UINT8)(-1)) || > + (Variable->DataSize =3D=3D (UINT32)(-1)) || > + (Variable->NameSize =3D=3D (UINT32)(-1)) || > + (Variable->Attributes =3D=3D (UINT32)(-1))) > + { > + return 0; > + } > + > + return (UINTN)Variable->DataSize; > + } > +} > + > +/** > + This code sets the size of variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] DataSize Data size to set. > + @param[in] AuthFormat TRUE indicates authenticated variables are used. > + FALSE indicates authenticated variables are not = used. > + > +**/ > +VOID > +SetDataSizeOfVariable ( > + IN VARIABLE_HEADER *Variable, > + IN UINTN DataSize, > + IN BOOLEAN AuthFormat > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + if (AuthFormat) { > + AuthVariable->DataSize =3D (UINT32)DataSize; > + } else { > + Variable->DataSize =3D (UINT32)DataSize; > + } > +} > + > +/** > + > + This code gets the pointer to the variable name. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to Variable Name which is Unicode encoding. > + > +**/ > +CHAR16 * > +GetVariableNamePtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFormat)= ); > +} > + > +/** > + This code gets the pointer to the variable guid. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return A EFI_GUID* pointer to Vendor Guid. > + > +**/ > +EFI_GUID * > +GetVendorGuidPtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + if (AuthFormat) { > + return &AuthVariable->VendorGuid; > + } else { > + return &Variable->VendorGuid; > + } > +} > + > +/** > + > + This code gets the pointer to the variable data. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to Variable Data. > + > +**/ > +UINT8 * > +GetVariableDataPtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + UINTN Value; > + > + // > + // Be careful about pad size for alignment. > + // > + Value =3D (UINTN)GetVariableNamePtr (Variable, AuthFormat); > + Value +=3D NameSizeOfVariable (Variable, AuthFormat); > + Value +=3D GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat)); > + > + return (UINT8 *)Value; > +} > + > +/** > + This code gets the variable data offset related to variable header. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Variable Data offset. > + > +**/ > +UINTN > +GetVariableDataOffset ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + UINTN Value; > + > + // > + // Be careful about pad size for alignment > + // > + Value =3D GetVariableHeaderSize (AuthFormat); > + Value +=3D NameSizeOfVariable (Variable, AuthFormat); > + Value +=3D GET_PAD_SIZE (NameSizeOfVariable (Variable, AuthFormat)); > + > + return Value; > +} > + > +/** > + Get variable data payload. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in,out] Data Pointer to buffer used to store the varia= ble data. > + @param[in,out] DataSize Size of buffer passed by Data. > + Size of data copied into Data buffer. > + @param[in] AuthFlag Auth-variable indicator. > + > + @return EFI_SUCCESS Data was fetched. > + @return EFI_INVALID_PARAMETER DataSize is NULL. > + @return EFI_BUFFER_TOO_SMALL DataSize is smaller than size of varia= ble > data. > + > +**/ > +EFI_STATUS > +GetVariableData ( > + IN VARIABLE_HEADER *Variable, > + IN OUT VOID *Data, > + IN OUT UINT32 *DataSize, > + IN BOOLEAN AuthFlag > + ) > +{ > + UINT32 Size; > + > + if (DataSize =3D=3D NULL) { > + ASSERT (DataSize !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Size =3D (UINT32)DataSizeOfVariable (Variable, AuthFlag); > + if (*DataSize < Size) { > + *DataSize =3D Size; > + return EFI_BUFFER_TOO_SMALL; > + } > + > + if (Data =3D=3D NULL) { > + ASSERT (Data !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + CopyMem (Data, GetVariableDataPtr (Variable, AuthFlag), Size); > + *DataSize =3D Size; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + This code gets the pointer to the next variable header. > + > + @param[in] Variable Pointer to the Variable Header. > + @param[in] AuthFormat TRUE indicates authenticated variables are use= d. > + FALSE indicates authenticated variables are no= t used. > + > + @return Pointer to next variable header. > + > +**/ > +VARIABLE_HEADER * > +GetNextVariablePtr ( > + IN VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFormat > + ) > +{ > + UINTN Value; > + > + Value =3D (UINTN)GetVariableDataPtr (Variable, AuthFormat); > + Value +=3D DataSizeOfVariable (Variable, AuthFormat); > + Value +=3D GET_PAD_SIZE (DataSizeOfVariable (Variable, AuthFormat)); > + > + // > + // Be careful about pad size for alignment. > + // > + return (VARIABLE_HEADER *)HEADER_ALIGN (Value); > +} > + > +/** > + > + Gets the pointer to the first variable header in given variable store = area. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @return Pointer to the first variable header. > + > +**/ > +VARIABLE_HEADER * > +GetStartPointer ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ) > +{ > + // > + // The start of variable store. > + // > + return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1); > +} > + > +/** > + > + Gets the pointer to the end of the variable storage area. > + > + This function gets pointer to the end of the variable storage > + area, according to the input variable store header. > + > + @param[in] VarStoreHeader Pointer to the Variable Store Header. > + > + @return Pointer to the end of the variable storage area. > + > +**/ > +VARIABLE_HEADER * > +GetEndPointer ( > + IN VARIABLE_STORE_HEADER *VarStoreHeader > + ) > +{ > + // > + // The end of variable store > + // > + return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + > VarStoreHeader->Size); > +} > + > +/** > + Compare two EFI_TIME data. > + > + > + @param[in] FirstTime A pointer to the first EFI_TIME data. > + @param[in] SecondTime A pointer to the second EFI_TIME data. > + > + @retval TRUE The FirstTime is not later than the SecondT= ime. > + @retval FALSE The FirstTime is later than the SecondTime. > + > +**/ > +BOOLEAN > +VariableCompareTimeStampInternal ( > + IN EFI_TIME *FirstTime, > + IN EFI_TIME *SecondTime > + ) > +{ > + if (FirstTime->Year !=3D SecondTime->Year) { > + return (BOOLEAN)(FirstTime->Year < SecondTime->Year); > + } else if (FirstTime->Month !=3D SecondTime->Month) { > + return (BOOLEAN)(FirstTime->Month < SecondTime->Month); > + } else if (FirstTime->Day !=3D SecondTime->Day) { > + return (BOOLEAN)(FirstTime->Day < SecondTime->Day); > + } else if (FirstTime->Hour !=3D SecondTime->Hour) { > + return (BOOLEAN)(FirstTime->Hour < SecondTime->Hour); > + } else if (FirstTime->Minute !=3D SecondTime->Minute) { > + return (BOOLEAN)(FirstTime->Minute < SecondTime->Minute); > + } > + > + return (BOOLEAN)(FirstTime->Second <=3D SecondTime->Second); > +} > + > +/** > + Find the variable in the specified variable store. > + > + @param[in] VariableName Name of the variable to be found > + @param[in] VendorGuid Vendor GUID to be found. > + @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCES= S > attribute > + check at runtime when searching v= ariable. > + @param[in, out] PtrTrack Variable Track Pointer structure = that contains > Variable Information. > + @param[in] AuthFormat TRUE indicates authenticated vari= ables are > used. > + FALSE indicates authenticated var= iables are not used. > + > + @retval EFI_SUCCESS Variable found successfully > + @retval EFI_NOT_FOUND Variable not found > +**/ > +EFI_STATUS > +FindVariableEx ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN BOOLEAN IgnoreRtCheck, > + IN OUT VARIABLE_POINTER_TRACK *PtrTrack, > + IN BOOLEAN AuthFormat > + ) > +{ > + VARIABLE_HEADER *InDeletedVariable; > + VOID *Point; > + > + PtrTrack->InDeletedTransitionPtr =3D NULL; > + > + // > + // Find the variable by walk through HOB, volatile and non-volatile va= riable > store. > + // > + InDeletedVariable =3D NULL; > + > + for ( PtrTrack->CurrPtr =3D PtrTrack->StartPtr > + ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr, Au= thFormat) > + ; PtrTrack->CurrPtr =3D GetNextVariablePtr (PtrTrack->CurrPtr, A= uthFormat) > + ) > + { > + if ((PtrTrack->CurrPtr->State =3D=3D VAR_ADDED) || > + (PtrTrack->CurrPtr->State =3D=3D (VAR_IN_DELETED_TRANSITION & > VAR_ADDED)) > + ) > + { > + if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attribu= tes & > EFI_VARIABLE_RUNTIME_ACCESS) !=3D 0)) { > + if (VariableName[0] =3D=3D 0) { > + if (PtrTrack->CurrPtr->State =3D=3D (VAR_IN_DELETED_TRANSITION= & > VAR_ADDED)) { > + InDeletedVariable =3D PtrTrack->CurrPtr; > + } else { > + PtrTrack->InDeletedTransitionPtr =3D InDeletedVariable; > + return EFI_SUCCESS; > + } > + } else { > + if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrP= tr, > AuthFormat))) { > + Point =3D (VOID *)GetVariableNamePtr (PtrTrack->CurrPtr, Aut= hFormat); > + > + ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr, AuthFormat) != =3D 0); > + if (CompareMem (VariableName, Point, NameSizeOfVariable (Ptr= Track- > >CurrPtr, AuthFormat)) =3D=3D 0) { > + if (PtrTrack->CurrPtr->State =3D=3D (VAR_IN_DELETED_TRANSI= TION & > VAR_ADDED)) { > + InDeletedVariable =3D PtrTrack->CurrPtr; > + } else { > + PtrTrack->InDeletedTransitionPtr =3D InDeletedVariable; > + return EFI_SUCCESS; > + } > + } > + } > + } > + } > + } > + } > + > + PtrTrack->CurrPtr =3D InDeletedVariable; > + return (PtrTrack->CurrPtr =3D=3D NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; > +} > + > +/** > + This code finds the next available variable. > + > + Caution: This function may receive untrusted input. > + This function may be invoked in SMM mode. This function will do basic > validation, before parse the data. > + > + @param[in] VariableName Pointer to variable name. > + @param[in] VendorGuid Variable Vendor Guid. > + @param[in] VariableStoreList A list of variable stores that should be= used to > get the next variable. > + The maximum number of entries is the max= value of > VARIABLE_STORE_TYPE. > + @param[out] VariablePtr Pointer to variable header address. > + @param[in] AuthFormat TRUE indicates authenticated variables a= re used. > + FALSE indicates authenticated variables = are not used. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND The next variable was not found. > + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, > while VendorGuid is NULL. > + @retval EFI_INVALID_PARAMETER The input values of VariableName and > VendorGuid are not a name and > + GUID of an existing variable. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceGetNextVariableInternal ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN VARIABLE_STORE_HEADER **VariableStoreList, > + OUT VARIABLE_HEADER **VariablePtr, > + IN BOOLEAN AuthFormat > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_STORE_TYPE StoreType; > + VARIABLE_POINTER_TRACK Variable; > + VARIABLE_POINTER_TRACK VariableInHob; > + VARIABLE_POINTER_TRACK VariablePtrTrack; > + > + Status =3D EFI_NOT_FOUND; > + > + if (VariableStoreList =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (&Variable, sizeof (Variable)); > + > + // Check if the variable exists in the given variable store list > + for (StoreType =3D (VARIABLE_STORE_TYPE)0; StoreType < > VariableStoreTypeMax; StoreType++) { > + if (VariableStoreList[StoreType] =3D=3D NULL) { > + continue; > + } > + > + Variable.StartPtr =3D GetStartPointer (VariableStoreList[StoreType])= ; > + Variable.EndPtr =3D GetEndPointer (VariableStoreList[StoreType]); > + Variable.Volatile =3D (BOOLEAN)(StoreType =3D=3D VariableStoreTypeVo= latile); > + > + Status =3D FindVariableEx (VariableName, VendorGuid, FALSE, &Variabl= e, > AuthFormat); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + > + if ((Variable.CurrPtr =3D=3D NULL) || EFI_ERROR (Status)) { > + // > + // For VariableName is an empty string, FindVariableEx() will try to= find and > return > + // the first qualified variable, and if FindVariableEx() returns err= or > (EFI_NOT_FOUND) > + // as no any variable is found, still go to return the error (EFI_NO= T_FOUND). > + // > + if (VariableName[0] !=3D 0) { > + // > + // For VariableName is not an empty string, and FindVariableEx() r= eturns > error as > + // VariableName and VendorGuid are not a name and GUID of an exist= ing > variable, > + // there is no way to get next variable, follow spec to return > EFI_INVALID_PARAMETER. > + // > + Status =3D EFI_INVALID_PARAMETER; > + } > + > + goto Done; > + } > + > + if (VariableName[0] !=3D 0) { > + // > + // If variable name is not empty, get next variable. > + // > + Variable.CurrPtr =3D GetNextVariablePtr (Variable.CurrPtr, AuthForma= t); > + } > + > + while (TRUE) { > + // > + // Switch to the next variable store if needed > + // > + while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr, > AuthFormat)) { > + // > + // Find current storage index > + // > + for (StoreType =3D (VARIABLE_STORE_TYPE)0; StoreType < > VariableStoreTypeMax; StoreType++) { > + if ((VariableStoreList[StoreType] !=3D NULL) && (Variable.StartP= tr =3D=3D > GetStartPointer (VariableStoreList[StoreType]))) { > + break; > + } > + } > + > + ASSERT (StoreType < VariableStoreTypeMax); > + // > + // Switch to next storage > + // > + for (StoreType++; StoreType < VariableStoreTypeMax; StoreType++) { > + if (VariableStoreList[StoreType] !=3D NULL) { > + break; > + } > + } > + > + // > + // Capture the case that > + // 1. current storage is the last one, or > + // 2. no further storage > + // > + if (StoreType =3D=3D VariableStoreTypeMax) { > + Status =3D EFI_NOT_FOUND; > + goto Done; > + } > + > + Variable.StartPtr =3D GetStartPointer (VariableStoreList[StoreType= ]); > + Variable.EndPtr =3D GetEndPointer (VariableStoreList[StoreType])= ; > + Variable.CurrPtr =3D Variable.StartPtr; > + } > + > + // > + // Variable is found > + // > + if ((Variable.CurrPtr->State =3D=3D VAR_ADDED) || (Variable.CurrPtr-= >State =3D=3D > (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) { > + if (!AtRuntime () || ((Variable.CurrPtr->Attributes & > EFI_VARIABLE_RUNTIME_ACCESS) !=3D 0)) { > + if (Variable.CurrPtr->State =3D=3D (VAR_IN_DELETED_TRANSITION & > VAR_ADDED)) { > + // > + // If it is a IN_DELETED_TRANSITION variable, > + // and there is also a same ADDED one at the same time, > + // don't return it. > + // > + VariablePtrTrack.StartPtr =3D Variable.StartPtr; > + VariablePtrTrack.EndPtr =3D Variable.EndPtr; > + Status =3D FindVariableEx ( > + GetVariableNamePtr (Variable.Cur= rPtr, AuthFormat), > + GetVendorGuidPtr (Variable.CurrP= tr, AuthFormat), > + FALSE, > + &VariablePtrTrack, > + AuthFormat > + ); > + if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State = =3D=3D > VAR_ADDED)) { > + Variable.CurrPtr =3D GetNextVariablePtr (Variable.CurrPtr, A= uthFormat); > + continue; > + } > + } > + > + // > + // Don't return NV variable when HOB overrides it > + // > + if ((VariableStoreList[VariableStoreTypeHob] !=3D NULL) && > (VariableStoreList[VariableStoreTypeNv] !=3D NULL) && > + (Variable.StartPtr =3D=3D GetStartPointer > (VariableStoreList[VariableStoreTypeNv])) > + ) > + { > + VariableInHob.StartPtr =3D GetStartPointer > (VariableStoreList[VariableStoreTypeHob]); > + VariableInHob.EndPtr =3D GetEndPointer > (VariableStoreList[VariableStoreTypeHob]); > + Status =3D FindVariableEx ( > + GetVariableNamePtr (Variable.CurrPt= r, AuthFormat), > + GetVendorGuidPtr (Variable.CurrPtr,= AuthFormat), > + FALSE, > + &VariableInHob, > + AuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + Variable.CurrPtr =3D GetNextVariablePtr (Variable.CurrPtr, A= uthFormat); > + continue; > + } > + } > + > + *VariablePtr =3D Variable.CurrPtr; > + Status =3D EFI_SUCCESS; > + goto Done; > + } > + } > + > + Variable.CurrPtr =3D GetNextVariablePtr (Variable.CurrPtr, AuthForma= t); > + } > + > +Done: > + return Status; > +} > + > +/** > + Routine used to track statistical information about variable usage. > + The data is stored in the EFI system table so it can be accessed later= . > + VariableInfo.efi can dump out the table. Only Boot Services variable > + accesses are tracked by this code. The PcdVariableCollectStatistics > + build flag controls if this feature is enabled. > + > + A read that hits in the cache will have Read and Cache true for > + the transaction. Data is allocated by this routine, but never > + freed. > + > + @param[in] VariableName Name of the Variable to track. > + @param[in] VendorGuid Guid of the Variable to track. > + @param[in] Volatile TRUE if volatile FALSE if non-volatile. > + @param[in] Read TRUE if GetVariable() was called. > + @param[in] Write TRUE if SetVariable() was called. > + @param[in] Delete TRUE if deleted via SetVariable(). > + @param[in] Cache TRUE for a cache hit. > + @param[in,out] VariableInfo Pointer to a pointer of VARIABLE_INFO_E= NTRY > structures. > + > +**/ > +VOID > +UpdateVariableInfo ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN BOOLEAN Volatile, > + IN BOOLEAN Read, > + IN BOOLEAN Write, > + IN BOOLEAN Delete, > + IN BOOLEAN Cache, > + IN OUT VARIABLE_INFO_ENTRY **VariableInfo > + ) > +{ > + VARIABLE_INFO_ENTRY *Entry; > + > + if (FeaturePcdGet (PcdVariableCollectStatistics)) { > + if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (Varia= bleInfo =3D=3D > NULL)) { > + return; > + } > + > + if (AtRuntime ()) { > + // Don't collect statistics at runtime. > + return; > + } > + > + if (*VariableInfo =3D=3D NULL) { > + // > + // On the first call allocate a entry and place a pointer to it in > + // the EFI System Table. > + // > + *VariableInfo =3D AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); > + ASSERT (*VariableInfo !=3D NULL); > + > + CopyGuid (&(*VariableInfo)->VendorGuid, VendorGuid); > + (*VariableInfo)->Name =3D AllocateZeroPool (StrSize (VariableName)= ); > + ASSERT ((*VariableInfo)->Name !=3D NULL); > + StrCpyS ((*VariableInfo)->Name, StrSize (VariableName)/sizeof (CHA= R16), > VariableName); > + (*VariableInfo)->Volatile =3D Volatile; > + } > + > + for (Entry =3D (*VariableInfo); Entry !=3D NULL; Entry =3D Entry->Ne= xt) { > + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { > + if (StrCmp (VariableName, Entry->Name) =3D=3D 0) { > + if (Read) { > + Entry->ReadCount++; > + } > + > + if (Write) { > + Entry->WriteCount++; > + } > + > + if (Delete) { > + Entry->DeleteCount++; > + } > + > + if (Cache) { > + Entry->CacheCount++; > + } > + > + return; > + } > + } > + > + if (Entry->Next =3D=3D NULL) { > + // > + // If the entry is not in the table add it. > + // Next iteration of the loop will fill in the data. > + // > + Entry->Next =3D AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); > + ASSERT (Entry->Next !=3D NULL); > + > + CopyGuid (&Entry->Next->VendorGuid, VendorGuid); > + Entry->Next->Name =3D AllocateZeroPool (StrSize (VariableName)); > + ASSERT (Entry->Next->Name !=3D NULL); > + StrCpyS (Entry->Next->Name, StrSize (VariableName)/sizeof (CHAR1= 6), > VariableName); > + Entry->Next->Volatile =3D Volatile; > + } > + } > + } > +} > + > +/** > + > + Retrieve details about a variable and return them in VariableInfo->Hea= der. > + > + If VariableInfo->Buffer is given, this function will calculate its off= set > + relative to given variable storage via VariableStore; Otherwise, it wi= ll try > + other internal variable storages or cached copies. It's assumed that, = for all > + copies of NV variable storage, all variables are stored in the same re= lative > + position. If VariableInfo->Buffer is found in the range of any storage= copies, > + its offset relative to that storage should be the same in other copies= . > + > + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Buff= er, > + this function will return the variable memory address inside VariableS= tore, > + if given, via VariableInfo->Address; Otherwise, the address of other s= torage > + copies will be returned, if any. > + > + For a new variable whose offset has not been determined, a value of -1= as > + VariableInfo->Offset should be passed to skip the offset calculation. > + > + @param[in,out] VariableInfo Pointer to variable informatio= n. > + > + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableIn= fo- > >Address > + and VariableInfo->Offset are NULL (0). > + @retval EFI_NOT_FOUND If given Address or Offset is out of ra= nge of > + any given or internal storage copies. > + @retval EFI_SUCCESS Variable details are retrieved successf= ully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetVariableInfo ( > + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo > + ) > +{ > + VARIABLE_STORE_HEADER *Stores[2]; > + UINTN Index; > + VARIABLE_HEADER *VariablePtr; > + VARIABLE_HEADER *VariableBuffer; > + AUTHENTICATED_VARIABLE_HEADER *AuthVariablePtr; > + BOOLEAN AuthFlag; > + UINTN NameSize; > + UINTN DataSize; > + UINTN VariableSize; > + > + if ((VariableInfo =3D=3D NULL) || ( (VariableInfo->Buffer =3D=3D NULL= ) > + && (VariableInfo->StoreIndex =3D=3D VAR_= INDEX_INVALID))) > + { > + ASSERT (VariableInfo !=3D NULL); > + ASSERT (VariableInfo->Buffer !=3D NULL || VariableInfo->StoreIndex != =3D > VAR_INDEX_INVALID); > + return EFI_INVALID_PARAMETER; > + } > + > + Stores[0] =3D mNvVariableCache; > + Stores[1] =3D (mVariableModuleGlobal !=3D NULL) > + ? (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.NonVolatileVariableBase > + : NULL; > + > + VariableBuffer =3D VariableInfo->Buffer; > + VariablePtr =3D NULL; > + if (VariableInfo->StoreIndex !=3D VAR_INDEX_INVALID) { > + for (Index =3D 0; Index < ARRAY_SIZE (Stores); ++Index) { > + if (Stores[Index] =3D=3D NULL) { > + continue; > + } > + > + if ((UINTN)VariableInfo->StoreIndex > + < ((UINTN)GetEndPointer (Stores[Index]) - (UINTN)Stores[Index]= )) > + { > + VariablePtr =3D (VARIABLE_HEADER *)((UINTN)Stores[Index= ] + > (UINTN)VariableInfo->StoreIndex); > + VariableInfo->Buffer =3D VariablePtr; > + break; > + } > + } > + } else { > + VariablePtr =3D VariableInfo->Buffer; > + } > + > + if (VariablePtr =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + AuthFlag =3D VariableInfo->Flags.Auth; > + ASSERT (AuthFlag =3D=3D TRUE || AuthFlag =3D=3D FALSE); > + > + // > + // Make a copy of the whole variable if a buffer is passed in. > + // > + if ((VariableBuffer !=3D NULL) && (VariableBuffer !=3D VariablePtr)) { > + VariableSize =3D (UINTN)GetNextVariablePtr (VariablePtr, AuthFlag) > + - (UINTN)VariablePtr; > + CopyMem (VariableBuffer, VariablePtr, VariableSize); > + } > + > + // > + // AuthVariable header > + // > + if (AuthFlag) { > + AuthVariablePtr =3D (AUTHENTICATED_VARIABLE_HEADER *)VariablePtr; > + > + VariableInfo->Header.State =3D AuthVariablePtr->State; > + VariableInfo->Header.Attributes =3D AuthVariablePtr->Attributes; > + VariableInfo->Header.PubKeyIndex =3D AuthVariablePtr->PubKeyIndex= ; > + VariableInfo->Header.MonotonicCount =3D ReadUnaligned64 ( > + &(AuthVariablePtr->Monotonic= Count) > + ); > + if (VariableInfo->Header.TimeStamp !=3D NULL) { > + CopyMem ( > + VariableInfo->Header.TimeStamp, > + &AuthVariablePtr->TimeStamp, > + sizeof (EFI_TIME) > + ); > + } else if (VariableBuffer !=3D NULL) { > + AuthVariablePtr =3D (AUTHENTICATED_VARIABLE_HEADER > *)VariableBuffer; > + VariableInfo->Header.TimeStamp =3D &AuthVariablePtr->TimeStamp; > + } > + } else { > + VariableInfo->Header.State =3D VariablePtr->State; > + VariableInfo->Header.Attributes =3D VariablePtr->Attributes; > + VariableInfo->Header.PubKeyIndex =3D 0; > + VariableInfo->Header.MonotonicCount =3D 0; > + VariableInfo->Header.TimeStamp =3D NULL; > + } > + > + // > + // VendorGuid > + // > + if (VariableInfo->Header.VendorGuid !=3D NULL) { > + CopyGuid ( > + VariableInfo->Header.VendorGuid, > + GetVendorGuidPtr (VariablePtr, AuthFlag) > + ); > + } else { > + VariableInfo->Header.VendorGuid =3D GetVendorGuidPtr (VariablePtr, > AuthFlag); > + } > + > + // > + // VariableName > + // > + NameSize =3D NameSizeOfVariable (VariablePtr, AuthFlag); > + if ( (VariableInfo->Header.VariableName !=3D NULL) > + && (VariableInfo->Header.NameSize >=3D NameSize)) > + { > + CopyMem ( > + VariableInfo->Header.VariableName, > + GetVariableNamePtr (VariablePtr, AuthFlag), > + NameSize > + ); > + } else if (VariableInfo->Header.VariableName !=3D NULL) { > + return EFI_BUFFER_TOO_SMALL; > + } else { > + VariableInfo->Header.VariableName =3D GetVariableNamePtr (VariablePt= r, > AuthFlag); > + } > + > + // > + // Data > + // > + DataSize =3D DataSizeOfVariable (VariablePtr, AuthFlag); > + if ( (VariableInfo->Header.Data !=3D NULL) > + && (VariableInfo->Header.DataSize >=3D DataSize)) > + { > + CopyMem ( > + VariableInfo->Header.Data, > + GetVariableDataPtr (VariablePtr, AuthFlag), > + NameSize > + ); > + } else if (VariableInfo->Header.Data !=3D NULL) { > + return EFI_BUFFER_TOO_SMALL; > + } else { > + VariableInfo->Header.Data =3D GetVariableDataPtr (VariablePtr, AuthF= lag); > + } > + > + // > + // Update size information about name & data. > + // > + VariableInfo->Header.NameSize =3D NameSize; > + VariableInfo->Header.DataSize =3D DataSize; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Retrieve details of the variable next to given variable within Variabl= eStore. > + > + If VariableInfo->StoreIndex is invalid, the first one in VariableStore= is returned. > + > + @param[in,out] VariableInfo Pointer to variable informatio= n. > + > + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL. > + @retval EFI_NOT_FOUND If the end of VariableStore is reached. > + @retval EFI_SUCCESS The next variable is retrieved successf= ully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetNextVariableInfo ( > + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo > + ) > +{ > + VARIABLE_STORE_HEADER *VarStore; > + VARIABLE_HEADER *VariablePtr; > + VARIABLE_HEADER *VariableStart; > + VARIABLE_HEADER *VariableEnd; > + BOOLEAN AuthFlag; > + > + if (VariableInfo =3D=3D NULL) { > + ASSERT (VariableInfo !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + if (mNvVariableCache !=3D NULL) { > + VarStore =3D mNvVariableCache; > + } else if (mVariableModuleGlobal !=3D NULL) { > + VarStore =3D (VARIABLE_STORE_HEADER *)(UINTN) > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariable= Base; > + } else { > + return EFI_NOT_FOUND; > + } > + > + VariableStart =3D GetStartPointer (VarStore); > + VariableEnd =3D GetEndPointer (VarStore); > + > + if ((VariableInfo->Flags.Auth !=3D TRUE) && (VariableInfo->Flags.Auth = !=3D FALSE)) > { > + VariableInfo->Flags.Auth =3D CompareGuid ( > + &VarStore->Signature, > + &gEfiAuthenticatedVariableGuid > + ); > + } > + > + AuthFlag =3D VariableInfo->Flags.Auth; > + > + if (VariableInfo->StoreIndex =3D=3D VAR_INDEX_INVALID) { > + VariablePtr =3D VariableStart; > + } else { > + VariablePtr =3D (VARIABLE_HEADER *) > + ((UINTN)VarStore + (UINTN)VariableInfo->StoreIndex); > + if (VariablePtr >=3D VariableEnd) { > + return EFI_NOT_FOUND; > + } > + > + VariablePtr =3D GetNextVariablePtr (VariablePtr, AuthFlag); > + } > + > + if (!IsValidVariableHeader (VariablePtr, VariableEnd, AuthFlag)) { > + return EFI_NOT_FOUND; > + } > + > + VariableInfo->StoreIndex =3D (UINTN)VariablePtr - (UINTN)VarStore; > + return GetVariableInfo (VariableInfo); > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm > mDxe.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm > mDxe.c > new file mode 100644 > index 000000000000..b2094fbcd6ea > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariablePolicySm > mDxe.c > @@ -0,0 +1,575 @@ > +/** @file -- VariablePolicySmmDxe.c > +This protocol allows communication with Variable Policy Engine. > + > +Copyright (c) Microsoft Corporation. > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include > + > +#include "Variable.h" > + > +EDKII_VARIABLE_POLICY_PROTOCOL mVariablePolicyProtocol; > +EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication; > + > +VOID *mMmCommunicationBuffer; > +UINTN mMmCommunicationBufferSize; > +EFI_LOCK mMmCommunicationLock; > + > +/** > + Internal helper function to consolidate communication method. > + > + @param[in,out] CommBuffer > + @param[in,out] CommSize Size of the CommBuffer. > + > + @retval EFI_STATUS Result from communication method. > + > +**/ > +STATIC > +EFI_STATUS > +InternalMmCommunicate ( > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommSize > + ) > +{ > + EFI_STATUS Status; > + > + if ((CommBuffer =3D=3D NULL) || (CommSize =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D mMmCommunication->Communicate (mMmCommunication, > CommBuffer, CommBuffer, CommSize); > + return Status; > +} > + > +/** > + This API function disables the variable policy enforcement. If it's > + already been called once, will return EFI_ALREADY_STARTED. > + > + @retval EFI_SUCCESS > + @retval EFI_ALREADY_STARTED Has already been called once this bo= ot. > + @retval EFI_WRITE_PROTECTED Interface has been locked until rebo= ot. > + @retval EFI_WRITE_PROTECTED Interface option is disabled by plat= form > PCD. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ProtocolDisableVariablePolicy ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommHeader; > + VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader; > + UINTN BufferSize; > + > + // Check the PCD for convenience. > + // This would also be rejected by the lib, but why go to MM if we don'= t have to? > + if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) { > + return EFI_WRITE_PROTECTED; > + } > + > + AcquireLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // Set up the MM communication. > + BufferSize =3D mMmCommunicationBufferSize; > + CommHeader =3D mMmCommunicationBuffer; > + PolicyHeader =3D (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader- > >Data; > + CopyGuid (&CommHeader->HeaderGuid, > &gVarCheckPolicyLibMmiHandlerGuid); > + CommHeader->MessageLength =3D BufferSize - OFFSET_OF > (EFI_MM_COMMUNICATE_HEADER, Data); > + PolicyHeader->Signature =3D VAR_CHECK_POLICY_COMM_SIG; > + PolicyHeader->Revision =3D VAR_CHECK_POLICY_COMM_REVISION; > + PolicyHeader->Command =3D VAR_CHECK_POLICY_COMMAND_DISABLE; > + > + Status =3D InternalMmCommunicate (CommHeader, &BufferSize); > + DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", > __FUNCTION__, Status)); > + > + ReleaseLockOnlyAtBootTime (&mMmCommunicationLock); > + > + return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result; > +} > + > +/** > + This API function returns whether or not the policy engine is > + currently being enforced. > + > + @param[out] State Pointer to a return value for whether the po= licy > enforcement > + is currently enabled. > + > + @retval EFI_SUCCESS > + @retval Others An error has prevented this command from com= pleting. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ProtocolIsVariablePolicyEnabled ( > + OUT BOOLEAN *State > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommHeader; > + VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader; > + VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS *CommandParams; > + UINTN BufferSize; > + > + if (State =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // Set up the MM communication. > + BufferSize =3D mMmCommunicationBufferSize; > + CommHeader =3D mMmCommunicationBuffer; > + PolicyHeader =3D (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader- > >Data; > + CommandParams =3D (VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS > *)(PolicyHeader + 1); > + CopyGuid (&CommHeader->HeaderGuid, > &gVarCheckPolicyLibMmiHandlerGuid); > + CommHeader->MessageLength =3D BufferSize - OFFSET_OF > (EFI_MM_COMMUNICATE_HEADER, Data); > + PolicyHeader->Signature =3D VAR_CHECK_POLICY_COMM_SIG; > + PolicyHeader->Revision =3D VAR_CHECK_POLICY_COMM_REVISION; > + PolicyHeader->Command =3D VAR_CHECK_POLICY_COMMAND_IS_ENABLED; > + > + Status =3D InternalMmCommunicate (CommHeader, &BufferSize); > + DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", > __FUNCTION__, Status)); > + > + if (!EFI_ERROR (Status)) { > + Status =3D PolicyHeader->Result; > + *State =3D CommandParams->State; > + } > + > + ReleaseLockOnlyAtBootTime (&mMmCommunicationLock); > + > + return Status; > +} > + > +/** > + This API function validates and registers a new policy with > + the policy enforcement engine. > + > + @param[in] NewPolicy Pointer to the incoming policy structure. > + > + @retval EFI_SUCCESS > + @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally > inconsistent. > + @retval EFI_ALREADY_STARTED An identical matching policy alrea= dy > exists. > + @retval EFI_WRITE_PROTECTED The interface has been locked unti= l the > next reboot. > + @retval EFI_UNSUPPORTED Policy enforcement has been disabl= ed. No > reason to add more policies. > + @retval EFI_ABORTED A calculation error has prevented = this function > from completing. > + @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any > more policies. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ProtocolRegisterVariablePolicy ( > + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommHeader; > + VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader; > + VOID *PolicyBuffer; > + UINTN BufferSize; > + UINTN RequiredSize; > + > + if (NewPolicy =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // First, make sure that the required size does not exceed the capabil= ities > + // of the MmCommunication buffer. > + RequiredSize =3D OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + sizeof > (VAR_CHECK_POLICY_COMM_HEADER); > + Status =3D SafeUintnAdd (RequiredSize, NewPolicy->Size, &Require= dSize); > + if (EFI_ERROR (Status) || (RequiredSize > mMmCommunicationBufferSize))= { > + DEBUG (( > + DEBUG_ERROR, > + "%a - Policy too large for buffer! %r, %d > %d \n", > + __FUNCTION__, > + Status, > + RequiredSize, > + mMmCommunicationBufferSize > + )); > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // Set up the MM communication. > + BufferSize =3D mMmCommunicationBufferSize; > + CommHeader =3D mMmCommunicationBuffer; > + PolicyHeader =3D (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader- > >Data; > + PolicyBuffer =3D (VOID *)(PolicyHeader + 1); > + CopyGuid (&CommHeader->HeaderGuid, > &gVarCheckPolicyLibMmiHandlerGuid); > + CommHeader->MessageLength =3D BufferSize - OFFSET_OF > (EFI_MM_COMMUNICATE_HEADER, Data); > + PolicyHeader->Signature =3D VAR_CHECK_POLICY_COMM_SIG; > + PolicyHeader->Revision =3D VAR_CHECK_POLICY_COMM_REVISION; > + PolicyHeader->Command =3D VAR_CHECK_POLICY_COMMAND_REGISTER; > + > + // Copy the policy into place. This copy is safe because we've already= tested > above. > + CopyMem (PolicyBuffer, NewPolicy, NewPolicy->Size); > + > + Status =3D InternalMmCommunicate (CommHeader, &BufferSize); > + DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", > __FUNCTION__, Status)); > + > + ReleaseLockOnlyAtBootTime (&mMmCommunicationLock); > + > + return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result; > +} > + > +/** > + This helper function takes care of the overhead of formatting, sending= , and > interpreting > + the results for a single DumpVariablePolicy request. > + > + @param[in] PageRequested The page of the paginated results from= MM. > 0 for metadata. > + @param[out] TotalSize The total size of the entire buffer. R= eturned as > part of metadata. > + @param[out] PageSize The size of the current page being ret= urned. Not > valid as part of metadata. > + @param[out] HasMore A flag indicating whether there are mo= re pages > after this one. > + @param[out] Buffer The start of the current page from MM. > + > + @retval EFI_SUCCESS Output params have been updated (e= ither > metadata or dump page). > + @retval EFI_INVALID_PARAMETER One of the output params is NULL. > + @retval Others Response from MM handler. > + > +**/ > +STATIC > +EFI_STATUS > +DumpVariablePolicyHelper ( > + IN UINT32 PageRequested, > + OUT UINT32 *TotalSize, > + OUT UINT32 *PageSize, > + OUT BOOLEAN *HasMore, > + OUT UINT8 **Buffer > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommHeader; > + VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader; > + VAR_CHECK_POLICY_COMM_DUMP_PARAMS *CommandParams; > + UINTN BufferSize; > + > + if ((TotalSize =3D=3D NULL) || (PageSize =3D=3D NULL) || (HasMore =3D= =3D NULL) || (Buffer > =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // Set up the MM communication. > + BufferSize =3D mMmCommunicationBufferSize; > + CommHeader =3D mMmCommunicationBuffer; > + PolicyHeader =3D (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader- > >Data; > + CommandParams =3D (VAR_CHECK_POLICY_COMM_DUMP_PARAMS > *)(PolicyHeader + 1); > + CopyGuid (&CommHeader->HeaderGuid, > &gVarCheckPolicyLibMmiHandlerGuid); > + CommHeader->MessageLength =3D BufferSize - OFFSET_OF > (EFI_MM_COMMUNICATE_HEADER, Data); > + PolicyHeader->Signature =3D VAR_CHECK_POLICY_COMM_SIG; > + PolicyHeader->Revision =3D VAR_CHECK_POLICY_COMM_REVISION; > + PolicyHeader->Command =3D VAR_CHECK_POLICY_COMMAND_DUMP; > + > + CommandParams->PageRequested =3D PageRequested; > + > + Status =3D InternalMmCommunicate (CommHeader, &BufferSize); > + DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", > __FUNCTION__, Status)); > + > + if (!EFI_ERROR (Status)) { > + Status =3D PolicyHeader->Result; > + *TotalSize =3D CommandParams->TotalSize; > + *PageSize =3D CommandParams->PageSize; > + *HasMore =3D CommandParams->HasMore; > + *Buffer =3D (UINT8 *)(CommandParams + 1); > + } > + > + return Status; > +} > + > +/** > + This API function will dump the entire contents of the variable policy= table. > + > + Similar to GetVariable, the first call can be made with a 0 size and i= t will return > + the size of the buffer required to hold the entire table. > + > + @param[out] Policy Pointer to the policy buffer. Can be NULL if S= ize is 0. > + @param[in,out] Size On input, the size of the output buffer. On ou= tput, the > size > + of the data returned. > + > + @retval EFI_SUCCESS Policy data is in the output buffe= r and Size has > been updated. > + @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero = and > Policy is NULL. > + @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold polic= y. Size > updated with required size. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ProtocolDumpVariablePolicy ( > + OUT UINT8 *Policy OPTIONAL, > + IN OUT UINT32 *Size > + ) > +{ > + EFI_STATUS Status; > + UINT8 *Source; > + UINT8 *Destination; > + UINT32 PolicySize; > + UINT32 PageSize; > + BOOLEAN HasMore; > + UINT32 PageIndex; > + > + if ((Size =3D=3D NULL) || ((*Size > 0) && (Policy =3D=3D NULL))) { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // Repeat this whole process until we either have a failure case or ge= t the > entire buffer. > + do { > + // First, we must check the zero page to determine the buffer size a= nd > + // reset the internal state. > + PolicySize =3D 0; > + PageSize =3D 0; > + HasMore =3D FALSE; > + Status =3D DumpVariablePolicyHelper (0, &PolicySize, &PageSize, = &HasMore, > &Source); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + // If we're good, we can at least check the required size now. > + if (*Size < PolicySize) { > + *Size =3D PolicySize; > + Status =3D EFI_BUFFER_TOO_SMALL; > + break; > + } > + > + // On further thought, let's update the size either way. > + *Size =3D PolicySize; > + // And get ready to ROCK. > + Destination =3D Policy; > + > + // Keep looping and copying until we're either done or freak out. > + for (PageIndex =3D 1; !EFI_ERROR (Status) && HasMore && PageIndex < > MAX_UINT32; PageIndex++) { > + Status =3D DumpVariablePolicyHelper (PageIndex, &PolicySize, &Page= Size, > &HasMore, &Source); > + if (!EFI_ERROR (Status)) { > + CopyMem (Destination, Source, PageSize); > + Destination +=3D PageSize; > + } > + } > + > + // Next, we check to see whether > + } while (Status =3D=3D EFI_TIMEOUT); > + > + ReleaseLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // There's currently no use for this, but it shouldn't be hard to impl= ement. > + return Status; > +} > + > +/** > + This API function locks the interface so that no more policy updates > + can be performed or changes made to the enforcement until the next boo= t. > + > + @retval EFI_SUCCESS > + @retval Others An error has prevented this command from com= pleting. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ProtocolLockVariablePolicy ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommHeader; > + VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader; > + UINTN BufferSize; > + > + AcquireLockOnlyAtBootTime (&mMmCommunicationLock); > + > + // Set up the MM communication. > + BufferSize =3D mMmCommunicationBufferSize; > + CommHeader =3D mMmCommunicationBuffer; > + PolicyHeader =3D (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader- > >Data; > + CopyGuid (&CommHeader->HeaderGuid, > &gVarCheckPolicyLibMmiHandlerGuid); > + CommHeader->MessageLength =3D BufferSize - OFFSET_OF > (EFI_MM_COMMUNICATE_HEADER, Data); > + PolicyHeader->Signature =3D VAR_CHECK_POLICY_COMM_SIG; > + PolicyHeader->Revision =3D VAR_CHECK_POLICY_COMM_REVISION; > + PolicyHeader->Command =3D VAR_CHECK_POLICY_COMMAND_LOCK; > + > + Status =3D InternalMmCommunicate (CommHeader, &BufferSize); > + DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", > __FUNCTION__, Status)); > + > + ReleaseLockOnlyAtBootTime (&mMmCommunicationLock); > + > + return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result; > +} > + > +/** > + This helper function locates the shared comm buffer and assigns it to = input > pointers. > + > + @param[in,out] BufferSize On input, the minimum buffer size requ= ired > INCLUDING the MM communicate header. > + On output, the size of the matching bu= ffer found. > + @param[out] LocatedBuffer A pointer to the matching buffer. > + > + @retval EFI_SUCCESS > + @retval EFI_INVALID_PARAMETER One of the output pointers was NUL= L. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate a > comm buffer. > + > +**/ > +STATIC > +EFI_STATUS > +InitMmCommonCommBuffer ( > + IN OUT UINTN *BufferSize, > + OUT VOID **LocatedBuffer > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D EFI_SUCCESS; > + > + // Make sure that we're working with good pointers. > + if ((BufferSize =3D=3D NULL) || (LocatedBuffer =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // Allocate the runtime memory for the comm buffer. > + *LocatedBuffer =3D AllocateRuntimePool (*BufferSize); > + if (*LocatedBuffer =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + *BufferSize =3D 0; > + } > + > + EfiInitializeLock (&mMmCommunicationLock, TPL_NOTIFY); > + > + return Status; > +} > + > +/** > + Convert internal pointer addresses to virtual addresses. > + > + @param[in] Event Event whose notification function is being invok= ed. > + @param[in] Context The pointer to the notification function's conte= xt, > which > + is implementation-dependent. > +**/ > +STATIC > +VOID > +EFIAPI > +VariablePolicyVirtualAddressCallback ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EfiConvertPointer (0, (VOID **)&mMmCommunication); > + EfiConvertPointer (0, (VOID **)&mMmCommunicationBuffer); > +} > + > +/** > + The driver's entry point. > + > + @param[in] ImageHandle The firmware allocated handle for the EFI imag= e. > + @param[in] SystemTable A pointer to the EFI System Table. > + > + @retval EFI_SUCCESS The entry point executed successfully. > + @retval other Some error occured when executing this entry p= oint. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariablePolicySmmDxeMain ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN ProtocolInstalled; > + BOOLEAN VirtualAddressChangeRegistered; > + EFI_EVENT VirtualAddressChangeEvent; > + > + Status =3D EFI_SUCCESS; > + ProtocolInstalled =3D FALSE; > + VirtualAddressChangeRegistered =3D FALSE; > + > + // Update the minimum buffer size. > + mMmCommunicationBufferSize =3D > VAR_CHECK_POLICY_MM_COMM_BUFFER_SIZE; > + // Locate the shared comm buffer to use for sending MM commands. > + Status =3D InitMmCommonCommBuffer (&mMmCommunicationBufferSize, > &mMmCommunicationBuffer); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to locate a viable MM comm > buffer! %r\n", __FUNCTION__, Status)); > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // Locate the MmCommunication protocol. > + Status =3D gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NUL= L, > (VOID **)&mMmCommunication); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to locate MmCommunication > protocol! %r\n", __FUNCTION__, Status)); > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // Configure the VariablePolicy protocol structure. > + mVariablePolicyProtocol.Revision =3D > EDKII_VARIABLE_POLICY_PROTOCOL_REVISION; > + mVariablePolicyProtocol.DisableVariablePolicy =3D > ProtocolDisableVariablePolicy; > + mVariablePolicyProtocol.IsVariablePolicyEnabled =3D > ProtocolIsVariablePolicyEnabled; > + mVariablePolicyProtocol.RegisterVariablePolicy =3D > ProtocolRegisterVariablePolicy; > + mVariablePolicyProtocol.DumpVariablePolicy =3D > ProtocolDumpVariablePolicy; > + mVariablePolicyProtocol.LockVariablePolicy =3D ProtocolLockVariab= lePolicy; > + > + // Register all the protocols and return the status. > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &ImageHandle, > + &gEdkiiVariablePolicyProtocolGuid, > + &mVariablePolicyProtocol, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to install protocol! %r\n", > __FUNCTION__, Status)); > + goto Exit; > + } else { > + ProtocolInstalled =3D TRUE; > + } > + > + // Normally, we might want to register a callback > + // to lock the interface, but this is integrated > + // into the existing callbacks in VaraiableSmm.c > + // and VariableDxe.c. > + > + // > + // Register a VirtualAddressChange callback for the MmComm protocol an= d > Comm buffer. > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + VariablePolicyVirtualAddressCallback, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &VirtualAddressChangeEvent > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a - Failed to create VirtualAddressChange > event! %r\n", __FUNCTION__, Status)); > + goto Exit; > + } else { > + VirtualAddressChangeRegistered =3D TRUE; > + } > + > +Exit: > + // > + // If we're about to return a failed status (and unload this driver), = we must first > undo anything that > + // has been successfully done. > + if (EFI_ERROR (Status)) { > + if (ProtocolInstalled) { > + gBS->UninstallProtocolInterface (&ImageHandle, > &gEdkiiVariablePolicyProtocolGuid, &mVariablePolicyProtocol); > + } > + > + if (VirtualAddressChangeRegistered) { > + gBS->CloseEvent (VirtualAddressChangeEvent); > + } > + } > + > + return Status; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.c > new file mode 100644 > index 000000000000..9bb30bc1e804 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeC > ache.c > @@ -0,0 +1,158 @@ > +/** @file > + Functions related to managing the UEFI variable runtime cache. This fi= le > should only include functions > + used by the SMM UEFI variable driver. > + > + Caution: This module requires additional review when modified. > + This driver will have external input - variable data. They may be inpu= t in SMM > mode. > + This external input must be validated carefully to avoid security issu= e like > + buffer overflow, integer overflow. > + > +Copyright (c) 2019, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; > +extern VARIABLE_STORE_HEADER *mNvVariableCache; > + > +/** > + Copies any pending updates to runtime variable caches. > + > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + @retval EFI_SUCCESS The volatile store was updated success= fully. > + > +**/ > +EFI_STATUS > +FlushPendingRuntimeVariableCacheUpdates ( > + VOID > + ) > +{ > + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext; > + > + VariableRuntimeCacheContext =3D &mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + > + if ((VariableRuntimeCacheContext->VariableRuntimeNvCache.Store =3D=3D = NULL) > || > + (VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store = =3D=3D > NULL) || > + (VariableRuntimeCacheContext->PendingUpdate =3D=3D NULL)) > + { > + return EFI_UNSUPPORTED; > + } > + > + if (*(VariableRuntimeCacheContext->PendingUpdate)) { > + if ((VariableRuntimeCacheContext->VariableRuntimeHobCache.Store !=3D > NULL) && > + (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0)) > + { > + CopyMem ( > + (VOID *)( > + ((UINT8 *)(UINTN)VariableRuntimeCacheContext- > >VariableRuntimeHobCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset > + ), > + (VOID *)( > + ((UINT8 *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.HobVariableBase) + > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeHobCache.PendingUpdateOffset =3D 0; > + } > + > + CopyMem ( > + (VOID *)( > + ((UINT8 *)(UINTN)VariableRuntimeCacheContext- > >VariableRuntimeNvCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + (VOID *)( > + ((UINT8 *)(UINTN)mNvVariableCache) + > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeNvCache.PendingUpdateOffset =3D 0; > + > + CopyMem ( > + (VOID *)( > + ((UINT8 *)(UINTN)VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.Store) + > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset > + ), > + (VOID *)( > + ((UINT8 *)(UINTN)mVariableModuleGlobal- > >VariableGlobal.VolatileVariableBase) + > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset > + ), > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength > + ); > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength =3D 0; > + VariableRuntimeCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset =3D 0; > + *(VariableRuntimeCacheContext->PendingUpdate) = =3D FALSE; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Synchronizes the runtime variable caches with all pending updates outs= ide > runtime. > + > + Ensures all conditions are met to maintain coherency for runtime cache > updates. This function will attempt > + to write the given update (and any other pending updates) if the ReadL= ock is > available. Otherwise, the > + update is added as a pending update for the given variable store and i= t will be > flushed to the runtime cache > + at the next opportunity the ReadLock is available. > + > + @param[in] VariableRuntimeCache Variable runtime cache structure for t= he > runtime cache being synchronized. > + @param[in] Offset Offset in bytes to apply the update. > + @param[in] Length Length of data in bytes of the update. > + > + @retval EFI_SUCCESS The update was added as a pending upda= te > successfully. If the variable runtime > + cache ReadLock was available, the runt= ime cache was > updated successfully. > + @retval EFI_UNSUPPORTED The volatile store to be updated is no= t > initialized properly. > + > +**/ > +EFI_STATUS > +SynchronizeRuntimeVariableCache ( > + IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, > + IN UINTN Offset, > + IN UINTN Length > + ) > +{ > + if (VariableRuntimeCache =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } else if (VariableRuntimeCache->Store =3D=3D NULL) { > + // The runtime cache may not be active or allocated yet. > + // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_Y= ET. > + return EFI_SUCCESS; > + } > + > + if ((mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate =3D=3D NULL) || > + (mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock =3D=3D NULL)) > + { > + return EFI_UNSUPPORTED; > + } > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) && > + (VariableRuntimeCache->PendingUpdateLength > 0)) > + { > + VariableRuntimeCache->PendingUpdateLength =3D > + (UINT32)( > + MAX ( > + (UINTN)(VariableRuntimeCache->PendingUpdateOffset + > VariableRuntimeCache->PendingUpdateLength), > + Offset + Length > + ) - MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffs= et, > Offset) > + ); > + VariableRuntimeCache->PendingUpdateOffset =3D > + (UINT32)MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffset, > Offset); > + } else { > + VariableRuntimeCache->PendingUpdateLength =3D (UINT32)Length; > + VariableRuntimeCache->PendingUpdateOffset =3D (UINT32)Offset; > + } > + > + *(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) =3D TRUE; > + > + if (*(mVariableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext.ReadLock) =3D=3D FALSE) { > + return FlushPendingRuntimeVariableCacheUpdates (); > + } > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c > new file mode 100644 > index 000000000000..f7bac0227577 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.c > @@ -0,0 +1,1268 @@ > +/** @file > + The sample implementation for SMM variable protocol. And this driver > + implements an SMI handler to communicate with the DXE runtime driver > + to provide variable services. > + > + Caution: This module requires additional review when modified. > + This driver will have external input - variable data and communicate b= uffer in > SMM mode. > + This external input must be validated carefully to avoid security issu= e like > + buffer overflow, integer overflow. > + > + SmmVariableHandler() will receive untrusted input and do basic validat= ion. > + > + Each sub function VariableServiceGetVariable(), > VariableServiceGetNextVariableName(), > + VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), > ReclaimForOS(), > + SmmVariableGetStatistics() should also do validation based on its own > knowledge. > + > +Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> +Copyright (c) 2018, Linaro, Ltd. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include > +#include "Variable.h" > +#include "VariableParsing.h" > +#include "VariableRuntimeCache.h" > + > +extern VARIABLE_STORE_HEADER *mNvVariableCache; > + > +BOOLEAN mAtRuntime =3D FALSE; > +UINT8 *mVariableBufferPayload =3D NULL; > +UINTN mVariableBufferPayloadSize; > + > +/** > + SecureBoot Hook for SetVariable. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + > +**/ > +VOID > +EFIAPI > +SecureBootHook ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + return; > +} > + > +/** > + > + This code sets variable in storage blocks (Volatile or Non-Volatile). > + > + @param VariableName Name of Variable to be found. > + @param VendorGuid Variable vendor GUID. > + @param Attributes Attribute value of the variabl= e found > + @param DataSize Size of Data found. If size is= less than the > + data, this value contains the = required size. > + @param Data Data pointer. > + > + @return EFI_INVALID_PARAMETER Invalid parameter. > + @return EFI_SUCCESS Set successfully. > + @return EFI_OUT_OF_RESOURCES Resource not enough to set var= iable. > + @return EFI_NOT_FOUND Not found. > + @return EFI_WRITE_PROTECTED Variable is read-only. > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmVariableSetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Disable write protection when the calling SetVariable() through > EFI_SMM_VARIABLE_PROTOCOL. > + // > + mRequestSource =3D VarCheckFromTrusted; > + Status =3D VariableServiceSetVariable ( > + VariableName, > + VendorGuid, > + Attributes, > + DataSize, > + Data > + ); > + mRequestSource =3D VarCheckFromUntrusted; > + return Status; > +} > + > +EFI_SMM_VARIABLE_PROTOCOL gSmmVariable =3D { > + VariableServiceGetVariable, > + VariableServiceGetNextVariableName, > + SmmVariableSetVariable, > + VariableServiceQueryVariableInfo > +}; > + > +EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck =3D { > + VarCheckRegisterSetVariableCheckHandler, > + VarCheckVariablePropertySet, > + VarCheckVariablePropertyGet > +}; > + > +/** > + Return TRUE if ExitBootServices () has been called. > + > + @retval TRUE If ExitBootServices () has been called. > +**/ > +BOOLEAN > +AtRuntime ( > + VOID > + ) > +{ > + return mAtRuntime; > +} > + > +/** > + Initializes a basic mutual exclusion lock. > + > + This function initializes a basic mutual exclusion lock to the release= d state > + and returns the lock. Each lock provides mutual exclusion access at i= ts task > + priority level. Since there is no preemption or multiprocessor suppor= t in EFI, > + acquiring the lock only consists of raising to the locks TPL. > + If Lock is NULL, then ASSERT(). > + If Priority is not a valid TPL value, then ASSERT(). > + > + @param Lock A pointer to the lock data structure to initialize. > + @param Priority EFI TPL is associated with the lock. > + > + @return The lock. > + > +**/ > +EFI_LOCK * > +InitializeLock ( > + IN OUT EFI_LOCK *Lock, > + IN EFI_TPL Priority > + ) > +{ > + return Lock; > +} > + > +/** > + Acquires lock only at boot time. Simply returns at runtime. > + > + This is a temperary function that will be removed when > + EfiAcquireLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiAcquireLock() at boot time, and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to acquire. > + > +**/ > +VOID > +AcquireLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > +} > + > +/** > + Releases lock only at boot time. Simply returns at runtime. > + > + This is a temperary function which will be removed when > + EfiReleaseLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiReleaseLock() at boot time and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to release. > + > +**/ > +VOID > +ReleaseLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > +} > + > +/** > + Retrieve the SMM Fault Tolerent Write protocol interface. > + > + @param[out] FtwProtocol The interface of SMM Ftw protocol > + > + @retval EFI_SUCCESS The SMM FTW protocol instance was found = and > returned in FtwProtocol. > + @retval EFI_NOT_FOUND The SMM FTW protocol instance was not > found. > + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. > + > +**/ > +EFI_STATUS > +GetFtwProtocol ( > + OUT VOID **FtwProtocol > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Locate Smm Fault Tolerent Write protocol > + // > + Status =3D gMmst->MmLocateProtocol ( > + &gEfiSmmFaultTolerantWriteProtocolGuid, > + NULL, > + FtwProtocol > + ); > + return Status; > +} > + > +/** > + Retrieve the SMM FVB protocol interface by HANDLE. > + > + @param[in] FvBlockHandle The handle of SMM FVB protocol that prov= ides > services for > + reading, writing, and erasing the target= block. > + @param[out] FvBlock The interface of SMM FVB protocol > + > + @retval EFI_SUCCESS The interface information for the specif= ied > protocol was returned. > + @retval EFI_UNSUPPORTED The device does not support the SMM FVB > protocol. > + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE > or FvBlock is NULL. > + > +**/ > +EFI_STATUS > +GetFvbByHandle ( > + IN EFI_HANDLE FvBlockHandle, > + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock > + ) > +{ > + // > + // To get the SMM FVB protocol interface on the handle > + // > + return gMmst->MmHandleProtocol ( > + FvBlockHandle, > + &gEfiSmmFirmwareVolumeBlockProtocolGuid, > + (VOID **)FvBlock > + ); > +} > + > +/** > + Function returns an array of handles that support the SMM FVB protocol > + in a buffer allocated from pool. > + > + @param[out] NumberHandles The number of handles returned in Buffer= . > + @param[out] Buffer A pointer to the buffer to return the re= quested > + array of handles that support SMM FVB p= rotocol. > + > + @retval EFI_SUCCESS The array of handles was returned in Buf= fer, and > the number of > + handles in Buffer was returned in Number= Handles. > + @retval EFI_NOT_FOUND No SMM FVB handle was found. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store > the matching results. > + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. > + > +**/ > +EFI_STATUS > +GetFvbCountAndBuffer ( > + OUT UINTN *NumberHandles, > + OUT EFI_HANDLE **Buffer > + ) > +{ > + EFI_STATUS Status; > + UINTN BufferSize; > + > + if ((NumberHandles =3D=3D NULL) || (Buffer =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + BufferSize =3D 0; > + *NumberHandles =3D 0; > + *Buffer =3D NULL; > + Status =3D gMmst->MmLocateHandle ( > + ByProtocol, > + &gEfiSmmFirmwareVolumeBlockProtocolGuid, > + NULL, > + &BufferSize, > + *Buffer > + ); > + if (EFI_ERROR (Status) && (Status !=3D EFI_BUFFER_TOO_SMALL)) { > + return EFI_NOT_FOUND; > + } > + > + *Buffer =3D AllocatePool (BufferSize); > + if (*Buffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status =3D gMmst->MmLocateHandle ( > + ByProtocol, > + &gEfiSmmFirmwareVolumeBlockProtocolGuid, > + NULL, > + &BufferSize, > + *Buffer > + ); > + > + *NumberHandles =3D BufferSize / sizeof (EFI_HANDLE); > + if (EFI_ERROR (Status)) { > + *NumberHandles =3D 0; > + FreePool (*Buffer); > + *Buffer =3D NULL; > + } > + > + return Status; > +} > + > +/** > + Get the variable statistics information from the information buffer po= inted by > gVariableInfo. > + > + Caution: This function may be invoked at SMM runtime. > + InfoEntry and InfoSize are external input. Care must be taken to make = sure > not security issue at runtime. > + > + @param[in, out] InfoEntry A pointer to the buffer of variable info= rmation > entry. > + On input, point to the variable informat= ion returned last time. > if > + InfoEntry->VendorGuid is zero, return th= e first information. > + On output, point to the next variable in= formation. > + @param[in, out] InfoSize On input, the size of the variable infor= mation > buffer. > + On output, the returned variable informa= tion size. > + > + @retval EFI_SUCCESS The variable information is found and re= turned > successfully. > + @retval EFI_UNSUPPORTED No variable inoformation exists in varia= ble > driver. The > + PcdVariableCollectStatistics should be s= et TRUE to support it. > + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next > variable information. > + @retval EFI_INVALID_PARAMETER Input parameter is invalid. > + > +**/ > +EFI_STATUS > +SmmVariableGetStatistics ( > + IN OUT VARIABLE_INFO_ENTRY *InfoEntry, > + IN OUT UINTN *InfoSize > + ) > +{ > + VARIABLE_INFO_ENTRY *VariableInfo; > + UINTN NameSize; > + UINTN StatisticsInfoSize; > + CHAR16 *InfoName; > + UINTN InfoNameMaxSize; > + EFI_GUID VendorGuid; > + > + if (InfoEntry =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + VariableInfo =3D gVariableInfo; > + if (VariableInfo =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + StatisticsInfoSize =3D sizeof (VARIABLE_INFO_ENTRY); > + if (*InfoSize < StatisticsInfoSize) { > + *InfoSize =3D StatisticsInfoSize; > + return EFI_BUFFER_TOO_SMALL; > + } > + > + InfoName =3D (CHAR16 *)(InfoEntry + 1); > + InfoNameMaxSize =3D (*InfoSize - sizeof (VARIABLE_INFO_ENTRY)); > + > + CopyGuid (&VendorGuid, &InfoEntry->VendorGuid); > + > + if (IsZeroGuid (&VendorGuid)) { > + // > + // Return the first variable info > + // > + NameSize =3D StrSize (VariableInfo->Name); > + StatisticsInfoSize =3D sizeof (VARIABLE_INFO_ENTRY) + NameSize; > + if (*InfoSize < StatisticsInfoSize) { > + *InfoSize =3D StatisticsInfoSize; > + return EFI_BUFFER_TOO_SMALL; > + } > + > + CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY)); > + CopyMem (InfoName, VariableInfo->Name, NameSize); > + *InfoSize =3D StatisticsInfoSize; > + return EFI_SUCCESS; > + } > + > + // > + // Get the next variable info > + // > + while (VariableInfo !=3D NULL) { > + if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) { > + NameSize =3D StrSize (VariableInfo->Name); > + if (NameSize <=3D InfoNameMaxSize) { > + if (CompareMem (VariableInfo->Name, InfoName, NameSize) =3D=3D 0= ) { > + // > + // Find the match one > + // > + VariableInfo =3D VariableInfo->Next; > + break; > + } > + } > + } > + > + VariableInfo =3D VariableInfo->Next; > + } > + > + if (VariableInfo =3D=3D NULL) { > + *InfoSize =3D 0; > + return EFI_SUCCESS; > + } > + > + // > + // Output the new variable info > + // > + NameSize =3D StrSize (VariableInfo->Name); > + StatisticsInfoSize =3D sizeof (VARIABLE_INFO_ENTRY) + NameSize; > + if (*InfoSize < StatisticsInfoSize) { > + *InfoSize =3D StatisticsInfoSize; > + return EFI_BUFFER_TOO_SMALL; > + } > + > + CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY)); > + CopyMem (InfoName, VariableInfo->Name, NameSize); > + *InfoSize =3D StatisticsInfoSize; > + > + return EFI_SUCCESS; > +} > + > +/** > + Communication service SMI Handler entry. > + > + This SMI handler provides services for the variable wrapper driver. > + > + Caution: This function may receive untrusted input. > + This variable data and communicate buffer are external input, so this = function > will do basic validation. > + Each sub function VariableServiceGetVariable(), > VariableServiceGetNextVariableName(), > + VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), > ReclaimForOS(), > + SmmVariableGetStatistics() should also do validation based on its own > knowledge. > + > + @param[in] DispatchHandle The unique handle assigned to this hand= ler by > SmiHandlerRegister(). > + @param[in] RegisterContext Points to an optional handler context w= hich > was specified when the > + handler was registered. > + @param[in, out] CommBuffer A pointer to a collection of data in me= mory > that will > + be conveyed from a non-SMM environment = into an SMM > environment. > + @param[in, out] CommBufferSize The size of the CommBuffer. > + > + @retval EFI_SUCCESS The interrupt was handled = and quiesced. > No other handlers > + should still be called. > + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been > quiesced but other handlers should > + still be called. > + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still > pending and other handlers should still > + be called. > + @retval EFI_INTERRUPT_PENDING The interrupt could not be > quiesced. > +**/ > +EFI_STATUS > +EFIAPI > +SmmVariableHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *RegisterContext, > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommBufferSize > + ) > +{ > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE > *SmmVariableHeader; > + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME > *GetNextVariableName; > + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO > *QueryVariableInfo; > + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE > *GetPayloadSize; > + SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *RuntimeVariableCacheContext; > + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *GetRuntimeCacheInfo; > + SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE > *VariableToLock; > + SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *CommVariableProperty; > + VARIABLE_INFO_ENTRY *VariableInfo= ; > + VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCach= eContext; > + VARIABLE_STORE_HEADER *VariableCach= e; > + UINTN InfoSize; > + UINTN NameBufferSiz= e; > + UINTN CommBufferPay= loadSize; > + UINTN TempCommBuffe= rSize; > + > + // > + // If input is invalid, stop processing this SMI > + // > + if ((CommBuffer =3D=3D NULL) || (CommBufferSize =3D=3D NULL)) { > + return EFI_SUCCESS; > + } > + > + TempCommBufferSize =3D *CommBufferSize; > + > + if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer > size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + CommBufferPayloadSize =3D TempCommBufferSize - > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; > + if (CommBufferPayloadSize > mVariableBufferPayloadSize) { > + DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer > payload size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, > TempCommBufferSize)) { > + DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer > in SMRAM or overflow!\n")); > + return EFI_SUCCESS; > + } > + > + SmmVariableFunctionHeader =3D (SMM_VARIABLE_COMMUNICATE_HEADER > *)CommBuffer; > + switch (SmmVariableFunctionHeader->Function) { > + case SMM_VARIABLE_FUNCTION_GET_VARIABLE: > + if (CommBufferPayloadSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { > + DEBUG ((DEBUG_ERROR, "GetVariable: SMM communication buffer size > invalid!\n")); > + return EFI_SUCCESS; > + } > + > + // > + // Copy the input communicate buffer payload to pre-allocated SMM > variable buffer payload. > + // > + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, > CommBufferPayloadSize); > + SmmVariableHeader =3D > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE > *)mVariableBufferPayload; > + if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || > + ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > SmmVariableHeader->DataSize)) > + { > + // > + // Prevent InfoSize overflow happen > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + InfoSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) > + + SmmVariableHeader->DataSize + SmmVariableHeader->Name= Size; > + > + // > + // SMRAM range check already covered before > + // > + if (InfoSize > CommBufferPayloadSize) { > + DEBUG ((DEBUG_ERROR, "GetVariable: Data size exceed communicatio= n > buffer size limit!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // The VariableSpeculationBarrier() call here is to ensure the pre= vious > + // range/content checks for the CommBuffer have been completed bef= ore > the > + // subsequent consumption of the CommBuffer content. > + // > + VariableSpeculationBarrier (); > + if ((SmmVariableHeader->NameSize < sizeof (CHAR16)) || > (SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - > 1] !=3D L'\0')) { > + // > + // Make sure VariableName is A Null-terminated string. > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + Status =3D VariableServiceGetVariable ( > + SmmVariableHeader->Name, > + &SmmVariableHeader->Guid, > + &SmmVariableHeader->Attributes, > + &SmmVariableHeader->DataSize, > + (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader- > >NameSize > + ); > + CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, > CommBufferPayloadSize); > + break; > + > + case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: > + if (CommBufferPayloadSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { > + DEBUG ((DEBUG_ERROR, "GetNextVariableName: SMM communication > buffer size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + // > + // Copy the input communicate buffer payload to pre-allocated SMM > variable buffer payload. > + // > + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, > CommBufferPayloadSize); > + GetNextVariableName =3D > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME > *)mVariableBufferPayload; > + if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { > + // > + // Prevent InfoSize overflow happen > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + InfoSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + > GetNextVariableName->NameSize; > + > + // > + // SMRAM range check already covered before > + // > + if (InfoSize > CommBufferPayloadSize) { > + DEBUG ((DEBUG_ERROR, "GetNextVariableName: Data size exceed > communication buffer size limit!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + NameBufferSize =3D CommBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); > + if ((NameBufferSize < sizeof (CHAR16)) || (GetNextVariableName- > >Name[NameBufferSize/sizeof (CHAR16) - 1] !=3D L'\0')) { > + // > + // Make sure input VariableName is A Null-terminated string. > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + Status =3D VariableServiceGetNextVariableName ( > + &GetNextVariableName->NameSize, > + GetNextVariableName->Name, > + &GetNextVariableName->Guid > + ); > + CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, > CommBufferPayloadSize); > + break; > + > + case SMM_VARIABLE_FUNCTION_SET_VARIABLE: > + if (CommBufferPayloadSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { > + DEBUG ((DEBUG_ERROR, "SetVariable: SMM communication buffer size > invalid!\n")); > + return EFI_SUCCESS; > + } > + > + // > + // Copy the input communicate buffer payload to pre-allocated SMM > variable buffer payload. > + // > + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, > CommBufferPayloadSize); > + SmmVariableHeader =3D > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE > *)mVariableBufferPayload; > + if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || > + ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > SmmVariableHeader->DataSize)) > + { > + // > + // Prevent InfoSize overflow happen > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + InfoSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) > + + SmmVariableHeader->DataSize + SmmVariableHeader->Name= Size; > + > + // > + // SMRAM range check already covered before > + // Data buffer should not contain SMM range > + // > + if (InfoSize > CommBufferPayloadSize) { > + DEBUG ((DEBUG_ERROR, "SetVariable: Data size exceed communicatio= n > buffer size limit!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // The VariableSpeculationBarrier() call here is to ensure the pre= vious > + // range/content checks for the CommBuffer have been completed bef= ore > the > + // subsequent consumption of the CommBuffer content. > + // > + VariableSpeculationBarrier (); > + if ((SmmVariableHeader->NameSize < sizeof (CHAR16)) || > (SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - > 1] !=3D L'\0')) { > + // > + // Make sure VariableName is A Null-terminated string. > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + Status =3D VariableServiceSetVariable ( > + SmmVariableHeader->Name, > + &SmmVariableHeader->Guid, > + SmmVariableHeader->Attributes, > + SmmVariableHeader->DataSize, > + (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader- > >NameSize > + ); > + break; > + > + case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) { > + DEBUG ((DEBUG_ERROR, "QueryVariableInfo: SMM communication buffe= r > size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + QueryVariableInfo =3D > (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO > *)SmmVariableFunctionHeader->Data; > + > + Status =3D VariableServiceQueryVariableInfo ( > + QueryVariableInfo->Attributes, > + &QueryVariableInfo->MaximumVariableStorageSize, > + &QueryVariableInfo->RemainingVariableStorageSize, > + &QueryVariableInfo->MaximumVariableSize > + ); > + break; > + > + case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) { > + DEBUG ((DEBUG_ERROR, "GetPayloadSize: SMM communication buffer > size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + GetPayloadSize =3D > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE > *)SmmVariableFunctionHeader->Data; > + GetPayloadSize->VariablePayloadSize =3D mVariableBufferPayloadSize= ; > + Status =3D EFI_SUCCESS; > + break; > + > + case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: > + if (AtRuntime ()) { > + Status =3D EFI_UNSUPPORTED; > + break; > + } > + > + if (!mEndOfDxe) { > + MorLockInitAtEndOfDxe (); > + Status =3D LockVariablePolicy (); > + ASSERT_EFI_ERROR (Status); > + mEndOfDxe =3D TRUE; > + VarCheckLibInitializeAtEndOfDxe (NULL); > + // > + // The initialization for variable quota. > + // > + InitializeVariableQuota (); > + } > + > + ReclaimForOS (); > + Status =3D EFI_SUCCESS; > + break; > + > + case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: > + mAtRuntime =3D TRUE; > + Status =3D EFI_SUCCESS; > + break; > + > + case SMM_VARIABLE_FUNCTION_GET_STATISTICS: > + VariableInfo =3D (VARIABLE_INFO_ENTRY *)SmmVariableFunctionHeader- > >Data; > + InfoSize =3D TempCommBufferSize - > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; > + > + // > + // Do not need to check SmmVariableFunctionHeader->Data in SMRAM > here. > + // It is covered by previous CommBuffer check > + // > + > + // > + // Do not need to check CommBufferSize buffer as it should point t= o > SMRAM > + // that was used by SMM core to cache CommSize from > SmmCommunication protocol. > + // > + > + Status =3D SmmVariableGetStatistics (VariableInfo, &InfoS= ize); > + *CommBufferSize =3D InfoSize + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; > + break; > + > + case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE: > + if (mEndOfDxe) { > + Status =3D EFI_ACCESS_DENIED; > + } else { > + VariableToLock =3D (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE > *)SmmVariableFunctionHeader->Data; > + Status =3D VariableLockRequestToLock ( > + NULL, > + VariableToLock->Name, > + &VariableToLock->Guid > + ); > + } > + > + break; > + case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET: > + if (mEndOfDxe) { > + Status =3D EFI_ACCESS_DENIED; > + } else { > + CommVariableProperty =3D > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *)SmmVariableFunctionHeader->Data; > + Status =3D VarCheckVariablePropertySet ( > + CommVariableProperty->Name, > + &CommVariableProperty->Guid, > + &CommVariableProperty->VariableProperty > + ); > + } > + > + break; > + case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET: > + if (CommBufferPayloadSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) > { > + DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: SMM > communication buffer size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + // > + // Copy the input communicate buffer payload to pre-allocated SMM > variable buffer payload. > + // > + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, > CommBufferPayloadSize); > + CommVariableProperty =3D > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *)mVariableBufferPayload; > + if ((UINTN)(~0) - CommVariableProperty->NameSize < OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) > { > + // > + // Prevent InfoSize overflow happen > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + InfoSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + > CommVariableProperty->NameSize; > + > + // > + // SMRAM range check already covered before > + // > + if (InfoSize > CommBufferPayloadSize) { > + DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: Data size exc= eed > communication buffer size limit!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // The VariableSpeculationBarrier() call here is to ensure the pre= vious > + // range/content checks for the CommBuffer have been completed bef= ore > the > + // subsequent consumption of the CommBuffer content. > + // > + VariableSpeculationBarrier (); > + if ((CommVariableProperty->NameSize < sizeof (CHAR16)) || > (CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof > (CHAR16) - 1] !=3D L'\0')) { > + // > + // Make sure VariableName is A Null-terminated string. > + // > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + Status =3D VarCheckVariablePropertyGet ( > + CommVariableProperty->Name, > + &CommVariableProperty->Guid, > + &CommVariableProperty->VariableProperty > + ); > + CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, > CommBufferPayloadSize); > + break; > + case > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM > communication buffer size invalid!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (mEndOfDxe) { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot in= it > context after end of DXE!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // Copy the input communicate buffer payload to the pre-allocated = SMM > variable payload buffer. > + // > + CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, > CommBufferPayloadSize); > + RuntimeVariableCacheContext =3D > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *)mVariableBufferPayload; > + > + // > + // Verify required runtime cache buffers are provided. > + // > + if ((RuntimeVariableCacheContext->RuntimeVolatileCache =3D=3D NULL= ) || > + (RuntimeVariableCacheContext->RuntimeNvCache =3D=3D NULL) || > + (RuntimeVariableCacheContext->PendingUpdate =3D=3D NULL) || > + (RuntimeVariableCacheContext->ReadLock =3D=3D NULL) || > + (RuntimeVariableCacheContext->HobFlushComplete =3D=3D NULL)) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required > runtime cache buffer is NULL!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // Verify minimum size requirements for the runtime variable store= buffers. > + // > + if (((RuntimeVariableCacheContext->RuntimeHobCache !=3D NULL) && > + (RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof > (VARIABLE_STORE_HEADER))) || > + (RuntimeVariableCacheContext->RuntimeVolatileCache->Size < siz= eof > (VARIABLE_STORE_HEADER)) || > + (RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof > (VARIABLE_STORE_HEADER))) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime > cache buffer size is invalid!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + // > + // Verify runtime buffers do not overlap with SMRAM ranges. > + // > + if ((RuntimeVariableCacheContext->RuntimeHobCache !=3D NULL) && > + !VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->RuntimeHobCache, > + (UINTN)RuntimeVariableCacheContext->RuntimeHobCache->Size > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > HOB cache buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->RuntimeVolatileCache, > + (UINTN)RuntimeVariableCacheContext->RuntimeVolatileCache->S= ize > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > volatile cache buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->RuntimeNvCache, > + (UINTN)RuntimeVariableCacheContext->RuntimeNvCache->Size > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > non-volatile cache buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->PendingUpdate, > + sizeof (*(RuntimeVariableCacheContext->PendingUpdate)) > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > cache pending update buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->ReadLock, > + sizeof (*(RuntimeVariableCacheContext->ReadLock)) > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > cache read lock buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + if (!VariableSmmIsBufferOutsideSmmValid ( > + (UINTN)RuntimeVariableCacheContext->HobFlushComplete, > + sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)) > + )) > + { > + DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime > cache HOB flush complete buffer in SMRAM or overflow!\n")); > + Status =3D EFI_ACCESS_DENIED; > + goto EXIT; > + } > + > + VariableCacheContext =3D &mVar= iableModuleGlobal- > >VariableGlobal.VariableRuntimeCacheContext; > + VariableCacheContext->VariableRuntimeHobCache.Store =3D > RuntimeVariableCacheContext->RuntimeHobCache; > + VariableCacheContext->VariableRuntimeVolatileCache.Store =3D > RuntimeVariableCacheContext->RuntimeVolatileCache; > + VariableCacheContext->VariableRuntimeNvCache.Store =3D > RuntimeVariableCacheContext->RuntimeNvCache; > + VariableCacheContext->PendingUpdate =3D > RuntimeVariableCacheContext->PendingUpdate; > + VariableCacheContext->ReadLock =3D > RuntimeVariableCacheContext->ReadLock; > + VariableCacheContext->HobFlushComplete =3D > RuntimeVariableCacheContext->HobFlushComplete; > + > + // Set up the intial pending request since the RT cache needs to b= e in sync > with SMM cache > + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = =3D > 0; > + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = =3D > 0; > + if ((mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) && > + (VariableCacheContext->VariableRuntimeHobCache.Store !=3D NULL= )) > + { > + VariableCache = =3D (VARIABLE_STORE_HEADER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLengt= h > =3D (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache)= ; > + CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store- > >Signature), &(VariableCache->Signature)); > + } > + > + VariableCache = =3D (VARIABLE_STORE_HEADER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateOffset =3D 0; > + VariableCacheContext- > >VariableRuntimeVolatileCache.PendingUpdateLength =3D > (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache); > + CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Sto= re- > >Signature), &(VariableCache->Signature)); > + > + VariableCache = =3D (VARIABLE_STORE_HEADER > *)(UINTN)mNvVariableCache; > + VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = =3D 0; > + VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = =3D > (UINT32)((UINTN)GetEndPointer (VariableCache) - (UINTN)VariableCache); > + CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store- > >Signature), &(VariableCache->Signature)); > + > + *(VariableCacheContext->PendingUpdate) =3D TRUE; > + *(VariableCacheContext->ReadLock) =3D FALSE; > + *(VariableCacheContext->HobFlushComplete) =3D FALSE; > + > + Status =3D EFI_SUCCESS; > + break; > + case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE: > + Status =3D FlushPendingRuntimeVariableCacheUpdates (); > + break; > + case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO: > + if (CommBufferPayloadSize < sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) { > + DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication > buffer size invalid!\n")); > + return EFI_SUCCESS; > + } > + > + GetRuntimeCacheInfo =3D > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *)SmmVariableFunctionHeader->Data; > + > + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) { > + VariableCache =3D (VARIABLE_STORE_HEA= DER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase; > + GetRuntimeCacheInfo->TotalHobStorageSize =3D VariableCache->Size= ; > + } else { > + GetRuntimeCacheInfo->TotalHobStorageSize =3D 0; > + } > + > + VariableCache =3D (VARIABLE_STOR= E_HEADER > *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; > + GetRuntimeCacheInfo->TotalVolatileStorageSize =3D VariableCache-= >Size; > + VariableCache =3D (VARIABLE_STOR= E_HEADER > *)(UINTN)mNvVariableCache; > + GetRuntimeCacheInfo->TotalNvStorageSize =3D (UINTN)Variabl= eCache- > >Size; > + GetRuntimeCacheInfo->AuthenticatedVariableUsage =3D > mVariableModuleGlobal->VariableGlobal.AuthFormat; > + > + Status =3D EFI_SUCCESS; > + break; > + > + default: > + Status =3D EFI_UNSUPPORTED; > + } > + > +EXIT: > + > + SmmVariableFunctionHeader->ReturnStatus =3D Status; > + > + return EFI_SUCCESS; > +} > + > +/** > + SMM END_OF_DXE protocol notification event handler. > + > + @param Protocol Points to the protocol's unique identifier > + @param Interface Points to the interface instance > + @param Handle The handle on which the interface was installed > + > + @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully > + > +**/ > +EFI_STATUS > +EFIAPI > +SmmEndOfDxeCallback ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "[Variable]SMM_END_OF_DXE is signaled\n")); > + MorLockInitAtEndOfDxe (); > + Status =3D LockVariablePolicy (); > + ASSERT_EFI_ERROR (Status); > + mEndOfDxe =3D TRUE; > + VarCheckLibInitializeAtEndOfDxe (NULL); > + // > + // The initialization for variable quota. > + // > + InitializeVariableQuota (); > + if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) { > + ReclaimForOS (); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Initializes variable write service for SMM. > + > +**/ > +VOID > +VariableWriteServiceInitializeSmm ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D ProtectedVariableLibWriteInit (); > + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { > + DEBUG ((DEBUG_ERROR, "Variable protection service: write-init failed= . > Status =3D %r\n", Status)); > + ASSERT_EFI_ERROR (Status); > + return; > + } > + > + Status =3D VariableWriteServiceInitialize (); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. = Status > =3D %r\n", Status)); > + } > + > + // > + // Notify the variable wrapper driver the variable write service is re= ady > + // > + VariableNotifySmmWriteReady (); > +} > + > +/** > + SMM Fault Tolerant Write protocol notification event handler. > + > + Non-Volatile variable write may needs FTW protocol to reclaim when > + writting variable. > + > + @param Protocol Points to the protocol's unique identifier > + @param Interface Points to the interface instance > + @param Handle The handle on which the interface was installed > + > + @retval EFI_SUCCESS SmmEventCallback runs successfully > + @retval EFI_NOT_FOUND The Fvb protocol for variable is not found. > + > + **/ > +EFI_STATUS > +EFIAPI > +SmmFtwNotificationEvent ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS VariableStoreBase; > + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; > + EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; > + EFI_PHYSICAL_ADDRESS NvStorageVariableBase; > + UINTN FtwMaxBlockSize; > + UINT32 NvStorageVariableSize; > + UINT64 NvStorageVariableSize64; > + > + if (mVariableModuleGlobal->FvbInstance !=3D NULL) { > + return EFI_SUCCESS; > + } > + > + // > + // Ensure SMM FTW protocol is installed. > + // > + Status =3D GetFtwProtocol ((VOID **)&FtwProtocol); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D GetVariableFlashNvStorageInfo (&NvStorageVariableBase, > &NvStorageVariableSize64); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SafeUint64ToUint32 (NvStorageVariableSize64, > &NvStorageVariableSize); > + // This driver currently assumes the size will be UINT32 so assert the= value is > safe for now. > + ASSERT_EFI_ERROR (Status); > + > + ASSERT (NvStorageVariableBase !=3D 0); > + VariableStoreBase =3D NvStorageVariableBase + mNvFvHeaderCache- > >HeaderLength; > + > + Status =3D FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize= ); > + if (!EFI_ERROR (Status)) { > + ASSERT (NvStorageVariableSize <=3D FtwMaxBlockSize); > + } > + > + // > + // Let NonVolatileVariableBase point to flash variable store base dire= ctly after > FTW ready. > + // > + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase =3D > VariableStoreBase; > + > + // > + // Find the proper FVB protocol for variable. > + // > + Status =3D GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProto= col); > + if (EFI_ERROR (Status)) { > + return EFI_NOT_FOUND; > + } > + > + mVariableModuleGlobal->FvbInstance =3D FvbProtocol; > + > + // > + // Initializes variable write service after FTW was ready. > + // > + VariableWriteServiceInitializeSmm (); > + > + return EFI_SUCCESS; > +} > + > +/** > + Variable Driver main entry point. The Variable driver places the 4 EFI > + runtime services in the EFI System Table and installs arch protocols > + for variable read and write services being available. It also register= s > + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE > event. > + > + @retval EFI_SUCCESS Variable service successfully initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmVariableServiceInitialize ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE VariableHandle; > + VOID *SmmFtwRegistration; > + VOID *SmmEndOfDxeRegistration; > + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; > + > + // > + // Initialize protected variable service, if enabled. > + // > + ContextIn.StructSize =3D sizeof (ContextIn); > + ContextIn.StructVersion =3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; > + > + ContextIn.FindVariableSmm =3D NULL; > + ContextIn.GetVariableInfo =3D GetVariableInfo; > + ContextIn.GetNextVariableInfo =3D GetNextVariableInfo; > + ContextIn.UpdateVariableStore =3D VariableExLibUpdateNvVariable; > + ContextIn.UpdateVariable =3D VariableExLibUpdateVariable; > + > + ContextIn.MaxVariableSize =3D (UINT32)GetMaxVariableSize (); > + ContextIn.VariableServiceUser =3D FromSmmModule; > + > + Status =3D ProtectedVariableLibInitialize (&ContextIn); > + if (EFI_ERROR (Status) && (Status !=3D EFI_UNSUPPORTED)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // > + // Variable initialize. > + // > + Status =3D VariableCommonInitialize (); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Install the Smm Variable Protocol on a new handle. > + // > + VariableHandle =3D NULL; > + Status =3D gMmst->MmInstallProtocolInterface ( > + &VariableHandle, > + &gEfiSmmVariableProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &gSmmVariable > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gMmst->MmInstallProtocolInterface ( > + &VariableHandle, > + &gEdkiiSmmVarCheckProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mSmmVarCheck > + ); > + ASSERT_EFI_ERROR (Status); > + > + mVariableBufferPayloadSize =3D GetMaxVariableSize () + > + OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - > + GetVariableHeaderSize (mVariableModuleGlo= bal- > >VariableGlobal.AuthFormat); > + > + Status =3D gMmst->MmAllocatePool ( > + EfiRuntimeServicesData, > + mVariableBufferPayloadSize, > + (VOID **)&mVariableBufferPayload > + ); > + ASSERT_EFI_ERROR (Status); > + > + /// > + /// Register SMM variable SMI handler > + /// > + VariableHandle =3D NULL; > + Status =3D gMmst->MmiHandlerRegister (SmmVariableHandler, > &gEfiSmmVariableProtocolGuid, &VariableHandle); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Notify the variable wrapper driver the variable service is ready > + // > + VariableNotifySmmReady (); > + > + // > + // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function. > + // > + Status =3D gMmst->MmRegisterProtocolNotify ( > + &gEfiMmEndOfDxeProtocolGuid, > + SmmEndOfDxeCallback, > + &SmmEndOfDxeRegistration > + ); > + ASSERT_EFI_ERROR (Status); > + > + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { > + // > + // Register FtwNotificationEvent () notify function. > + // > + Status =3D gMmst->MmRegisterProtocolNotify ( > + &gEfiSmmFaultTolerantWriteProtocolGuid, > + SmmFtwNotificationEvent, > + &SmmFtwRegistration > + ); > + ASSERT_EFI_ERROR (Status); > + > + SmmFtwNotificationEvent (NULL, NULL, NULL); > + } else { > + // > + // Emulated non-volatile variable mode does not depend on FVB and FT= W. > + // > + VariableWriteServiceInitializeSmm (); > + } > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.c > new file mode 100644 > index 000000000000..b88f75370ad8 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.c > @@ -0,0 +1,1895 @@ > +/** @file > + Implement all four UEFI Runtime Variable services for the nonvolatile > + and volatile storage space and install variable architecture protocol > + based on SMM variable module. > + > + Caution: This module requires additional review when modified. > + This driver will have external input - variable data. > + This external input must be validated carefully to avoid security issu= e like > + buffer overflow, integer overflow. > + > + RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are extern= al API > + to receive data buffer. The size should be checked carefully. > + > + InitCommunicateBuffer() is really function to check the variable data = size. > + > +Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
> +Copyright (c) Microsoft Corporation.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include "PrivilegePolymorphic.h" > +#include "Variable.h" > +#include "VariableParsing.h" > + > +EFI_HANDLE mHandle =3D= NULL; > +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable =3D= NULL; > +EFI_EVENT mVirtualAddressChangeEvent =3D= NULL; > +EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 =3D > NULL; > +UINT8 *mVariableBuffer =3D= NULL; > +UINT8 *mVariableBufferPhysical =3D= NULL; > +VARIABLE_INFO_ENTRY *mVariableInfo =3D= NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer =3D > NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer =3D= NULL; > +VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer =3D > NULL; > +VARIABLE_STORE_HEADER *mNvVariableCache =3D= NULL; > +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal =3D= NULL; > +UINTN mVariableBufferSize; > +UINTN mVariableRuntimeHobCacheBufferSize; > +UINTN mVariableRuntimeNvCacheBufferSize; > +UINTN mVariableRuntimeVolatileCacheBufferSize; > +UINTN mVariableBufferPayloadSize; > +BOOLEAN mVariableRuntimeCachePendingUpdate; > +BOOLEAN mVariableRuntimeCacheReadLock; > +BOOLEAN mVariableAuthFormat; > +BOOLEAN mHobFlushComplete; > +EFI_LOCK mVariableServicesLock; > +EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock; > +EDKII_VAR_CHECK_PROTOCOL mVarCheck; > + > +/** > + The logic to initialize the VariablePolicy engine is in its own file. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariablePolicySmmDxeMain ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ); > + > +/** > + Some Secure Boot Policy Variable may update following other variable > changes(SecureBoot follows PK change, etc). > + Record their initial State when variable write service is ready. > + > +**/ > +VOID > +EFIAPI > +RecordSecureBootPolicyVarData ( > + VOID > + ); > + > +/** > + Acquires lock only at boot time. Simply returns at runtime. > + > + This is a temperary function that will be removed when > + EfiAcquireLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiAcquireLock() at boot time, and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to acquire. > + > +**/ > +VOID > +AcquireLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > + if (!EfiAtRuntime ()) { > + EfiAcquireLock (Lock); > + } > +} > + > +/** > + Releases lock only at boot time. Simply returns at runtime. > + > + This is a temperary function which will be removed when > + EfiReleaseLock() in UefiLib can handle the call in UEFI > + Runtimer driver in RT phase. > + It calls EfiReleaseLock() at boot time and simply returns > + at runtime. > + > + @param Lock A pointer to the lock to release. > + > +**/ > +VOID > +ReleaseLockOnlyAtBootTime ( > + IN EFI_LOCK *Lock > + ) > +{ > + if (!EfiAtRuntime ()) { > + EfiReleaseLock (Lock); > + } > +} > + > +/** > + Return TRUE if ExitBootServices () has been called. > + > + @retval TRUE If ExitBootServices () has been called. FALSE if ExitBoot= Services > () has not been called. > +**/ > +BOOLEAN > +AtRuntime ( > + VOID > + ) > +{ > + return EfiAtRuntime (); > +} > + > +/** > + Initialize the variable cache buffer as an empty variable store. > + > + @param[out] VariableCacheBuffer A pointer to pointer of a cach= e > variable store. > + @param[in,out] TotalVariableCacheSize On input, the minimum size nee= ded > for the UEFI variable store cache > + buffer that is allocated. On o= utput, the actual size of the > buffer allocated. > + If TotalVariableCacheSize is z= ero, a buffer will not be > allocated and the > + function will return with EFI_= SUCCESS. > + > + @retval EFI_SUCCESS The variable cache was allocated and i= nitialized > successfully. > + @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid > variable store size was specified. > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available t= o > allocate the variable store cache buffer. > + > +**/ > +EFI_STATUS > +InitVariableCache ( > + OUT VARIABLE_STORE_HEADER **VariableCacheBuffer, > + IN OUT UINTN *TotalVariableCacheSize > + ) > +{ > + VARIABLE_STORE_HEADER *VariableCacheStorePtr; > + EFI_STATUS Status; > + > + if (TotalVariableCacheSize =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (*TotalVariableCacheSize =3D=3D 0) { > + return EFI_SUCCESS; > + } > + > + if ((VariableCacheBuffer =3D=3D NULL) || (*TotalVariableCacheSize < si= zeof > (VARIABLE_STORE_HEADER))) { > + return EFI_INVALID_PARAMETER; > + } > + > + *TotalVariableCacheSize =3D ALIGN_VALUE (*TotalVariableCacheSize, size= of > (UINT32)); > + > + // > + // Allocate NV Storage Cache and initialize it to all 1's (like an era= sed FV) > + // > + *VariableCacheBuffer =3D (VARIABLE_STORE_HEADER *)AllocateRuntimePage= s > ( > + EFI_SIZE_TO_PAGES (= *TotalVariableCacheSize) > + ); > + if (*VariableCacheBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Request to unblock the newly allocated cache region to be accessibl= e from > inside MM > + // > + Status =3D MmUnblockMemoryRequest ( > + (EFI_PHYSICAL_ADDRESS)(UINTN)*VariableCacheBuffer, > + EFI_SIZE_TO_PAGES (*TotalVariableCacheSize) > + ); > + if ((Status !=3D EFI_UNSUPPORTED) && EFI_ERROR (Status)) { > + return Status; > + } > + > + VariableCacheStorePtr =3D *VariableCacheBuffer; > + SetMem32 ((VOID *)VariableCacheStorePtr, *TotalVariableCacheSize, > (UINT32)0xFFFFFFFF); > + > + ZeroMem ((VOID *)VariableCacheStorePtr, sizeof > (VARIABLE_STORE_HEADER)); > + VariableCacheStorePtr->Size =3D (UINT32)*TotalVariableCacheSize; > + VariableCacheStorePtr->Format =3D VARIABLE_STORE_FORMATTED; > + VariableCacheStorePtr->State =3D VARIABLE_STORE_HEALTHY; > + > + return EFI_SUCCESS; > +} > + > +/** > + Initialize the communicate buffer using DataSize and Function. > + > + The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + > + DataSize. > + > + Caution: This function may receive untrusted input. > + The data size external input, so this function will validate it carefu= lly to avoid > buffer overflow. > + > + @param[out] DataPtr Points to the data in the communicat= e buffer. > + @param[in] DataSize The data size to send to SMM. > + @param[in] Function The function number to initialize th= e > communicate header. > + > + @retval EFI_INVALID_PARAMETER The data size is too big. > + @retval EFI_SUCCESS Find the specified variable. > + > +**/ > +EFI_STATUS > +InitCommunicateBuffer ( > + OUT VOID **DataPtr OPTIONAL, > + IN UINTN DataSize, > + IN UINTN Function > + ) > +{ > + EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; > + > + if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) { > + return EFI_INVALID_PARAMETER; > + } > + > + SmmCommunicateHeader =3D (EFI_MM_COMMUNICATE_HEADER > *)mVariableBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D DataSize + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; > + SmmVariableFunctionHeader->Function =3D Function; > + if (DataPtr !=3D NULL) { > + *DataPtr =3D SmmVariableFunctionHeader->Data; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Send the data in communicate buffer to SMM. > + > + @param[in] DataSize This size of the function header a= nd the data. > + > + @retval EFI_SUCCESS Success is returned from the funct= in in SMM. > + @retval Others Failure is returned from the funct= ion in SMM. > + > +**/ > +EFI_STATUS > +SendCommunicateBuffer ( > + IN UINTN DataSize > + ) > +{ > + EFI_STATUS Status; > + UINTN CommSize; > + EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; > + > + CommSize =3D DataSize + SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; > + Status =3D mMmCommunication2->Communicate ( > + mMmCommunication2, > + mVariableBufferPhysical, > + mVariableBuffer, > + &CommSize > + ); > + ASSERT_EFI_ERROR (Status); > + > + SmmCommunicateHeader =3D (EFI_MM_COMMUNICATE_HEADER > *)mVariableBuffer; > + SmmVariableFunctionHeader =3D (SMM_VARIABLE_COMMUNICATE_HEADER > *)SmmCommunicateHeader->Data; > + return SmmVariableFunctionHeader->ReturnStatus; > +} > + > +/** > + Mark a variable that will become read-only after leaving the DXE phase= of > execution. > + > + @param[in] This The VARIABLE_LOCK_PROTOCOL instance. > + @param[in] VariableName A pointer to the variable name that will be m= ade > read-only subsequently. > + @param[in] VendorGuid A pointer to the vendor GUID that will be mad= e > read-only subsequently. > + > + @retval EFI_SUCCESS The variable specified by the VariableNa= me and > the VendorGuid was marked > + as pending to be read-only. > + @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL. > + Or VariableName is an empty string. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the > lock request. > +**/ > +EFI_STATUS > +EFIAPI > +VariableLockRequestToLock ( > + IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This, > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN VariableNameSize; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock; > + > + if ((VariableName =3D=3D NULL) || (VariableName[0] =3D=3D 0) || (Vendo= rGuid =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + VariableNameSize =3D StrSize (VariableName); > + VariableToLock =3D NULL; > + > + // > + // If VariableName exceeds SMM payload limit. Return failure > + // > + if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + PayloadSize =3D OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, > Name) + VariableNameSize; > + Status =3D InitCommunicateBuffer ((VOID **)&VariableToLock, Paylo= adSize, > SMM_VARIABLE_FUNCTION_LOCK_VARIABLE); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (VariableToLock !=3D NULL); > + > + CopyGuid (&VariableToLock->Guid, VendorGuid); > + VariableToLock->NameSize =3D VariableNameSize; > + CopyMem (VariableToLock->Name, VariableName, VariableToLock- > >NameSize); > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Register SetVariable check handler. > + > + @param[in] Handler Pointer to check handler. > + > + @retval EFI_SUCCESS The SetVariable check handler was regist= ered > successfully. > + @retval EFI_INVALID_PARAMETER Handler is NULL. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > SetVariable check handler register request. > + @retval EFI_UNSUPPORTED This interface is not implemented. > + For example, it is unsupported in VarChe= ck protocol if both > VarCheck and SmmVarCheck protocols are present. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckRegisterSetVariableCheckHandler ( > + IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler > + ) > +{ > + return EFI_UNSUPPORTED; > +} > + > +/** > + Variable property set. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[in] VariableProperty Pointer to the input variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was set successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string, > + or the fields of VariableProperty are no= t valid. > + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or > EFI_EVENT_GROUP_READY_TO_BOOT has > + already been signaled. > + @retval EFI_OUT_OF_RESOURCES There is not enough resource for the > variable property set request. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertySet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ) > +{ > + EFI_STATUS Status; > + UINTN VariableNameSize= ; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *CommVariableProperty; > + > + if ((Name =3D=3D NULL) || (Name[0] =3D=3D 0) || (Guid =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (VariableProperty =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (VariableProperty->Revision !=3D > VAR_CHECK_VARIABLE_PROPERTY_REVISION) { > + return EFI_INVALID_PARAMETER; > + } > + > + VariableNameSize =3D StrSize (Name); > + CommVariableProperty =3D NULL; > + > + // > + // If VariableName exceeds SMM payload limit. Return failure > + // > + if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) > { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + > VariableNameSize; > + Status =3D InitCommunicateBuffer ((VOID **)&CommVariableProperty, > PayloadSize, > SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (CommVariableProperty !=3D NULL); > + > + CopyGuid (&CommVariableProperty->Guid, Guid); > + CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, > sizeof (*VariableProperty)); > + CommVariableProperty->NameSize =3D VariableNameSize; > + CopyMem (CommVariableProperty->Name, Name, CommVariableProperty- > >NameSize); > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Variable property get. > + > + @param[in] Name Pointer to the variable name. > + @param[in] Guid Pointer to the vendor GUID. > + @param[out] VariableProperty Pointer to the output variable property. > + > + @retval EFI_SUCCESS The property of variable specified by th= e Name > and Guid was got successfully. > + @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, > or Name is an empty string. > + @retval EFI_NOT_FOUND The property of variable specified by th= e Name > and Guid was not found. > + > +**/ > +EFI_STATUS > +EFIAPI > +VarCheckVariablePropertyGet ( > + IN CHAR16 *Name, > + IN EFI_GUID *Guid, > + OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty > + ) > +{ > + EFI_STATUS Status; > + UINTN VariableNameSize= ; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY > *CommVariableProperty; > + > + if ((Name =3D=3D NULL) || (Name[0] =3D=3D 0) || (Guid =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (VariableProperty =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + VariableNameSize =3D StrSize (Name); > + CommVariableProperty =3D NULL; > + > + // > + // If VariableName exceeds SMM payload limit. Return failure > + // > + if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) > { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + > VariableNameSize; > + Status =3D InitCommunicateBuffer ((VOID **)&CommVariableProperty, > PayloadSize, > SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (CommVariableProperty !=3D NULL); > + > + CopyGuid (&CommVariableProperty->Guid, Guid); > + CommVariableProperty->NameSize =3D VariableNameSize; > + CopyMem (CommVariableProperty->Name, Name, CommVariableProperty- > >NameSize); > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + if (Status =3D=3D EFI_SUCCESS) { > + CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, > sizeof (*VariableProperty)); > + } > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Signals SMM to synchronize any pending variable updates with the runti= me > cache(s). > + > +**/ > +VOID > +SyncRuntimeCache ( > + VOID > + ) > +{ > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. > + // > + InitCommunicateBuffer (NULL, 0, > SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE); > + > + // > + // Send data to SMM. > + // > + SendCommunicateBuffer (0); > +} > + > +/** > + Check whether a SMI must be triggered to retrieve pending cache update= s. > + > + If the variable HOB was finished being flushed since the last check fo= r a > runtime cache update, this function > + will prevent the HOB cache from being used for future runtime cache hi= ts. > + > +**/ > +VOID > +CheckForRuntimeCacheSync ( > + VOID > + ) > +{ > + if (mVariableRuntimeCachePendingUpdate) { > + SyncRuntimeCache (); > + } > + > + ASSERT (!mVariableRuntimeCachePendingUpdate); > + > + // > + // The HOB variable data may have finished being flushed in the runtim= e cache > sync update > + // > + if (mHobFlushComplete && (mVariableRuntimeHobCacheBuffer !=3D NULL)) { > + if (!EfiAtRuntime ()) { > + FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES > (mVariableRuntimeHobCacheBufferSize)); > + } > + > + mVariableRuntimeHobCacheBuffer =3D NULL; > + } > +} > + > +/** > + Finds the given variable in a runtime cache variable store. > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully to > avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be= found. > + > +**/ > +EFI_STATUS > +FindVariableInRuntimeCache ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_POINTER_TRACK RtPtrTrack; > + VARIABLE_STORE_TYPE StoreType; > + VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax]; > + > + Status =3D EFI_NOT_FOUND; > + > + if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (DataSiz= e =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack)); > + > + // > + // The UEFI specification restricts Runtime Services callers from invo= king the > same or certain other Runtime Service > + // functions prior to completion and return from a previous Runtime Se= rvice > call. These restrictions prevent > + // a GetVariable () or GetNextVariable () call from being issued until= a prior call > has returned. The runtime > + // cache read lock should always be free when entering this function. > + // > + ASSERT (!mVariableRuntimeCacheReadLock); > + > + mVariableRuntimeCacheReadLock =3D TRUE; > + CheckForRuntimeCacheSync (); > + > + if (!mVariableRuntimeCachePendingUpdate) { > + // > + // 0: Volatile, 1: HOB, 2: Non-Volatile. > + // The index and attributes mapping must be kept in this order as > FindVariable > + // makes use of this mapping to implement search algorithm. > + // > + VariableStoreList[VariableStoreTypeVolatile] =3D > mVariableRuntimeVolatileCacheBuffer; > + VariableStoreList[VariableStoreTypeHob] =3D > mVariableRuntimeHobCacheBuffer; > + VariableStoreList[VariableStoreTypeNv] =3D > mVariableRuntimeNvCacheBuffer; > + > + for (StoreType =3D (VARIABLE_STORE_TYPE)0; StoreType < > VariableStoreTypeMax; StoreType++) { > + if (VariableStoreList[StoreType] =3D=3D NULL) { > + continue; > + } > + > + RtPtrTrack.StartPtr =3D GetStartPointer (VariableStoreList[StoreTy= pe]); > + RtPtrTrack.EndPtr =3D GetEndPointer (VariableStoreList[StoreType= ]); > + RtPtrTrack.Volatile =3D (BOOLEAN)(StoreType =3D=3D VariableStoreTy= peVolatile); > + > + Status =3D FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtr= Track, > mVariableAuthFormat); > + if (!EFI_ERROR (Status)) { > + break; > + } > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // Get data size > + // > + if (!RtPtrTrack.Volatile) { > + // > + // Currently only non-volatile variable needs protection. > + // > + Status =3D ProtectedVariableLibGetByBuffer (RtPtrTrack.CurrPtr, = Data, > (UINT32 *)DataSize, mVariableAuthFormat); > + } > + > + if (RtPtrTrack.Volatile || (Status =3D=3D EFI_UNSUPPORTED)) { > + Status =3D GetVariableData (RtPtrTrack.CurrPtr, Data, (UINT32 *)= DataSize, > mVariableAuthFormat); > + } > + > + if (!EFI_ERROR (Status)) { > + UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatil= e, > TRUE, FALSE, FALSE, FALSE, &mVariableInfo); > + } > + } > + } > + > + if ((Status =3D=3D EFI_SUCCESS) || (Status =3D=3D EFI_BUFFER_TOO_SMALL= )) { > + if ((Attributes !=3D NULL) && (RtPtrTrack.CurrPtr !=3D NULL)) { > + *Attributes =3D RtPtrTrack.CurrPtr->Attributes; > + } > + } > + > + mVariableRuntimeCacheReadLock =3D FALSE; > + > + return Status; > +} > + > +/** > + Finds the given variable in a variable store in SMM. > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully to > avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be= found. > + > +**/ > +EFI_STATUS > +EFIAPI > +FindVariableInSmm ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; > + UINTN TempDataSize; > + UINTN VariableNameSize; > + > + if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (DataSiz= e =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + TempDataSize =3D *DataSize; > + VariableNameSize =3D StrSize (VariableName); > + SmmVariableHeader =3D NULL; > + > + // > + // If VariableName exceeds SMM payload limit. Return failure > + // > + if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - > VariableNameSize) { > + // > + // If output data buffer exceed SMM payload limit. Trim output buffe= r to > SMM payload size > + // > + TempDataSize =3D mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - > VariableNameSize; > + } > + > + PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > VariableNameSize + TempDataSize; > + > + Status =3D InitCommunicateBuffer ((VOID **)&SmmVariableHeader, Payload= Size, > SMM_VARIABLE_FUNCTION_GET_VARIABLE); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (SmmVariableHeader !=3D NULL); > + > + CopyGuid (&SmmVariableHeader->Guid, VendorGuid); > + SmmVariableHeader->DataSize =3D TempDataSize; > + SmmVariableHeader->NameSize =3D VariableNameSize; > + if (Attributes =3D=3D NULL) { > + SmmVariableHeader->Attributes =3D 0; > + } else { > + SmmVariableHeader->Attributes =3D *Attributes; > + } > + > + CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader- > >NameSize); > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + > + // > + // Get data from SMM. > + // > + if ((Status =3D=3D EFI_SUCCESS) || (Status =3D=3D EFI_BUFFER_TOO_SMALL= )) { > + // > + // SMM CommBuffer DataSize can be a trimed value > + // Only update DataSize when needed > + // > + *DataSize =3D SmmVariableHeader->DataSize; > + } > + > + if (Attributes !=3D NULL) { > + *Attributes =3D SmmVariableHeader->Attributes; > + } > + > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + if (Data !=3D NULL) { > + CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + > SmmVariableHeader->NameSize, SmmVariableHeader->DataSize); > + } else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + > +Done: > + return Status; > +} > + > +/** > + This code finds variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + The data size is external input, so this function will validate it car= efully to > avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[out] Attributes Attribute value of the variable fou= nd. > + @param[in, out] DataSize Size of Data found. If size is less= than the > + data, this value contains the requi= red size. > + @param[out] Data Data pointer. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Find the specified variable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + > +**/ > +EFI_STATUS > +EFIAPI > +RuntimeServiceGetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + OUT UINT32 *Attributes OPTIONAL, > + IN OUT UINTN *DataSize, > + OUT VOID *Data > + ) > +{ > + EFI_STATUS Status; > + > + if ((VariableName =3D=3D NULL) || (VendorGuid =3D=3D NULL) || (DataSiz= e =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (VariableName[0] =3D=3D 0) { > + return EFI_NOT_FOUND; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + Status =3D FindVariableInRuntimeCache (VariableName, VendorGuid, Att= ributes, > DataSize, Data); > + } else { > + Status =3D FindVariableInSmm (VariableName, VendorGuid, Attributes, = DataSize, > Data); > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + > + return Status; > +} > + > +/** > + Finds the next available variable in a runtime cache variable store. > + > + @param[in, out] VariableNameSize Size of the variable name. > + @param[in, out] VariableName Pointer to variable name. > + @param[in, out] VendorGuid Variable Vendor Guid. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Find the specified variable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + > +**/ > +EFI_STATUS > +GetNextVariableNameInRuntimeCache ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN VarNameSize; > + VARIABLE_HEADER *VariablePtr; > + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; > + > + Status =3D EFI_NOT_FOUND; > + > + // > + // The UEFI specification restricts Runtime Services callers from invo= king the > same or certain other Runtime Service > + // functions prior to completion and return from a previous Runtime Se= rvice > call. These restrictions prevent > + // a GetVariable () or GetNextVariable () call from being issued until= a prior call > has returned. The runtime > + // cache read lock should always be free when entering this function. > + // > + ASSERT (!mVariableRuntimeCacheReadLock); > + > + CheckForRuntimeCacheSync (); > + > + mVariableRuntimeCacheReadLock =3D TRUE; > + if (!mVariableRuntimeCachePendingUpdate) { > + // > + // 0: Volatile, 1: HOB, 2: Non-Volatile. > + // The index and attributes mapping must be kept in this order as > FindVariable > + // makes use of this mapping to implement search algorithm. > + // > + VariableStoreHeader[VariableStoreTypeVolatile] =3D > mVariableRuntimeVolatileCacheBuffer; > + VariableStoreHeader[VariableStoreTypeHob] =3D > mVariableRuntimeHobCacheBuffer; > + VariableStoreHeader[VariableStoreTypeNv] =3D > mVariableRuntimeNvCacheBuffer; > + > + Status =3D VariableServiceGetNextVariableInternal ( > + VariableName, > + VendorGuid, > + VariableStoreHeader, > + &VariablePtr, > + mVariableAuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + VarNameSize =3D NameSizeOfVariable (VariablePtr, mVariableAuthForm= at); > + ASSERT (VarNameSize !=3D 0); > + if (VarNameSize <=3D *VariableNameSize) { > + CopyMem (VariableName, GetVariableNamePtr (VariablePtr, > mVariableAuthFormat), VarNameSize); > + CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, > mVariableAuthFormat), sizeof (EFI_GUID)); > + Status =3D EFI_SUCCESS; > + } else { > + Status =3D EFI_BUFFER_TOO_SMALL; > + } > + > + *VariableNameSize =3D VarNameSize; > + } > + } > + > + mVariableRuntimeCacheReadLock =3D FALSE; > + > + return Status; > +} > + > +/** > + Finds the next available variable in a SMM variable store. > + > + @param[in, out] VariableNameSize Size of the variable name. > + @param[in, out] VariableName Pointer to variable name. > + @param[in, out] VendorGuid Variable Vendor Guid. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Find the specified variable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + > +**/ > +EFI_STATUS > +GetNextVariableNameInSmm ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME > *SmmGetNextVariableName; > + UINTN OutVariableNameSize; > + UINTN InVariableNameSize; > + > + OutVariableNameSize =3D *VariableNameSize; > + InVariableNameSize =3D StrSize (VariableName); > + SmmGetNextVariableName =3D NULL; > + > + // > + // If input string exceeds SMM payload limit. Return failure > + // > + if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) { > + // > + // If output buffer exceed SMM payload limit. Trim output buffer to = SMM > payload size > + // > + OutVariableNameSize =3D mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name); > + } > + > + // > + // Payload should be Guid + NameSize + MAX of Input & Output buffer > + // > + PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX > (OutVariableNameSize, InVariableNameSize); > + > + Status =3D InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, > PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (SmmGetNextVariableName !=3D NULL); > + > + // > + // SMM comm buffer->NameSize is buffer size for return string > + // > + SmmGetNextVariableName->NameSize =3D OutVariableNameSize; > + > + CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid); > + // > + // Copy whole string > + // > + CopyMem (SmmGetNextVariableName->Name, VariableName, > InVariableNameSize); > + if (OutVariableNameSize > InVariableNameSize) { > + ZeroMem ((UINT8 *)SmmGetNextVariableName->Name + > InVariableNameSize, OutVariableNameSize - InVariableNameSize); > + } > + > + // > + // Send data to SMM > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + > + // > + // Get data from SMM. > + // > + if ((Status =3D=3D EFI_SUCCESS) || (Status =3D=3D EFI_BUFFER_TOO_SMALL= )) { > + // > + // SMM CommBuffer NameSize can be a trimed value > + // Only update VariableNameSize when needed > + // > + *VariableNameSize =3D SmmGetNextVariableName->NameSize; > + } > + > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid); > + CopyMem (VariableName, SmmGetNextVariableName->Name, > SmmGetNextVariableName->NameSize); > + > +Done: > + return Status; > +} > + > +/** > + This code Finds the Next available variable. > + > + @param[in, out] VariableNameSize Size of the variable name. > + @param[in, out] VariableName Pointer to variable name. > + @param[in, out] VendorGuid Variable Vendor Guid. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Find the specified variable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the resul= t. > + > +**/ > +EFI_STATUS > +EFIAPI > +RuntimeServiceGetNextVariableName ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VendorGuid > + ) > +{ > + EFI_STATUS Status; > + UINTN MaxLen; > + > + Status =3D EFI_NOT_FOUND; > + > + if ((VariableNameSize =3D=3D NULL) || (VariableName =3D=3D NULL) || (V= endorGuid =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Calculate the possible maximum length of name string, including the= Null > terminator. > + // > + MaxLen =3D *VariableNameSize / sizeof (CHAR16); > + if ((MaxLen =3D=3D 0) || (StrnLenS (VariableName, MaxLen) =3D=3D MaxLe= n)) { > + // > + // Null-terminator is not found in the first VariableNameSize bytes = of the > input VariableName buffer, > + // follow spec to return EFI_INVALID_PARAMETER. > + // > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + Status =3D GetNextVariableNameInRuntimeCache (VariableNameSize, > VariableName, VendorGuid); > + } else { > + Status =3D GetNextVariableNameInSmm (VariableNameSize, VariableName, > VendorGuid); > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + > + return Status; > +} > + > +/** > + This code sets variable in storage blocks (Volatile or Non-Volatile). > + > + Caution: This function may receive untrusted input. > + The data size and data are external input, so this function will valid= ate it > carefully to avoid buffer overflow. > + > + @param[in] VariableName Name of Variable to be found. > + @param[in] VendorGuid Variable vendor GUID. > + @param[in] Attributes Attribute value of the variabl= e found > + @param[in] DataSize Size of Data found. If size is= less than the > + data, this value contains the = required size. > + @param[in] Data Data pointer. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_SUCCESS Set successfully. > + @retval EFI_OUT_OF_RESOURCES Resource not enough to set var= iable. > + @retval EFI_NOT_FOUND Not found. > + @retval EFI_WRITE_PROTECTED Variable is read-only. > + > +**/ > +EFI_STATUS > +EFIAPI > +RuntimeServiceSetVariable ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT32 Attributes, > + IN UINTN DataSize, > + IN VOID *Data > + ) > +{ > + EFI_STATUS Status; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; > + UINTN VariableNameSize; > + > + // > + // Check input parameters. > + // > + if ((VariableName =3D=3D NULL) || (VariableName[0] =3D=3D 0) || (Vendo= rGuid =3D=3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((DataSize !=3D 0) && (Data =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + VariableNameSize =3D StrSize (VariableName); > + SmmVariableHeader =3D NULL; > + > + // > + // If VariableName or DataSize exceeds SMM payload limit. Return failu= re > + // > + if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) || > + (DataSize > mVariableBufferPayloadSize - OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - > VariableNameSize)) > + { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. > + // > + PayloadSize =3D OFFSET_OF > (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + > VariableNameSize + DataSize; > + Status =3D InitCommunicateBuffer ((VOID **)&SmmVariableHeader, > PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (SmmVariableHeader !=3D NULL); > + > + CopyGuid ((EFI_GUID *)&SmmVariableHeader->Guid, VendorGuid); > + SmmVariableHeader->DataSize =3D DataSize; > + SmmVariableHeader->NameSize =3D VariableNameSize; > + SmmVariableHeader->Attributes =3D Attributes; > + CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader- > >NameSize); > + CopyMem ((UINT8 *)SmmVariableHeader->Name + SmmVariableHeader- > >NameSize, Data, DataSize); > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + > + if (!EfiAtRuntime ()) { > + if (!EFI_ERROR (Status)) { > + SecureBootHook ( > + VariableName, > + VendorGuid > + ); > + } > + } > + > + return Status; > +} > + > +/** > + This code returns information about the EFI variables. > + > + @param[in] Attributes Attributes bitmask to specify= the type of > variables > + on which to return informatio= n. > + @param[out] MaximumVariableStorageSize Pointer to the maximum size o= f > the storage space available > + for the EFI variables associa= ted with the attributes > specified. > + @param[out] RemainingVariableStorageSize Pointer to the remaining size= of > the storage space available > + for EFI variables associated = with the attributes specified. > + @param[out] MaximumVariableSize Pointer to the maximum size o= f an > individual EFI variables > + associated with the attribute= s specified. > + > + @retval EFI_INVALID_PARAMETER An invalid combination of att= ribute > bits was supplied. > + @retval EFI_SUCCESS Query successfully. > + @retval EFI_UNSUPPORTED The attribute is not supporte= d on this > platform. > + > +**/ > +EFI_STATUS > +EFIAPI > +RuntimeServiceQueryVariableInfo ( > + IN UINT32 Attributes, > + OUT UINT64 *MaximumVariableStorageSize, > + OUT UINT64 *RemainingVariableStorageSize, > + OUT UINT64 *MaximumVariableSize > + ) > +{ > + EFI_STATUS Status; > + UINTN PayloadSize; > + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO > *SmmQueryVariableInfo; > + > + SmmQueryVariableInfo =3D NULL; > + > + if ((MaximumVariableStorageSize =3D=3D NULL) || (RemainingVariableStor= ageSize > =3D=3D NULL) || (MaximumVariableSize =3D=3D NULL) || (Attributes =3D=3D 0= )) { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize; > + // > + PayloadSize =3D sizeof > (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO); > + Status =3D InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, > PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + ASSERT (SmmQueryVariableInfo !=3D NULL); > + > + SmmQueryVariableInfo->Attributes =3D Attributes; > + > + // > + // Send data to SMM. > + // > + Status =3D SendCommunicateBuffer (PayloadSize); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data from SMM. > + // > + *MaximumVariableSize =3D SmmQueryVariableInfo->MaximumVariabl= eSize; > + *MaximumVariableStorageSize =3D SmmQueryVariableInfo- > >MaximumVariableStorageSize; > + *RemainingVariableStorageSize =3D SmmQueryVariableInfo- > >RemainingVariableStorageSize; > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Exit Boot Services Event notification handler. > + > + Notify SMM variable driver about the event. > + > + @param[in] Event Event whose notification function is being invok= ed. > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +OnExitBootServices ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. > + // > + InitCommunicateBuffer (NULL, 0, > SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); > + > + // > + // Send data to SMM. > + // > + SendCommunicateBuffer (0); > +} > + > +/** > + On Ready To Boot Services Event notification handler. > + > + Notify SMM variable driver about the event. > + > + @param[in] Event Event whose notification function is being invok= ed > + @param[in] Context Pointer to the notification function's context > + > +**/ > +VOID > +EFIAPI > +OnReadyToBoot ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. > + // > + InitCommunicateBuffer (NULL, 0, > SMM_VARIABLE_FUNCTION_READY_TO_BOOT); > + > + // > + // Send data to SMM. > + // > + SendCommunicateBuffer (0); > + > + // > + // Install the system configuration table for variable info data captu= red > + // > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet > (PcdVariableCollectStatistics)) { > + if (mVariableAuthFormat) { > + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, > mVariableInfo); > + } else { > + gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo); > + } > + } > + > + gBS->CloseEvent (Event); > +} > + > +/** > + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. > + > + This is a notification function registered on > EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. > + It convers pointer to new virtual address. > + > + @param[in] Event Event whose notification function is being in= voked. > + @param[in] Context Pointer to the notification function's contex= t. > + > +**/ > +VOID > +EFIAPI > +VariableAddressChangeEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EfiConvertPointer (0x0, (VOID **)&mVariableBuffer); > + EfiConvertPointer (0x0, (VOID **)&mMmCommunication2); > + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID > **)&mVariableRuntimeHobCacheBuffer); > + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID > **)&mVariableRuntimeNvCacheBuffer); > + EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID > **)&mVariableRuntimeVolatileCacheBuffer); > +} > + > +/** > + This code gets variable payload size. > + > + @param[out] VariablePayloadSize Output pointer to variable payload s= ize. > + > + @retval EFI_SUCCESS Get successfully. > + @retval Others Get unsuccessfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetVariablePayloadSize ( > + OUT UINTN *VariablePayloadSize > + ) > +{ > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize; > + EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + UINTN CommSize; > + UINT8 *CommBuffer; > + > + SmmGetPayloadSize =3D NULL; > + CommBuffer =3D NULL; > + > + if (VariablePayloadSize =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); > + // > + CommSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); > + CommBuffer =3D AllocateZeroPool (CommSize); > + if (CommBuffer =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + SmmCommunicateHeader =3D (EFI_MM_COMMUNICATE_HEADER > *)CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE); > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; > + SmmVariableFunctionHeader->Function =3D > SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE; > + SmmGetPayloadSize =3D > (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE > *)SmmVariableFunctionHeader->Data; > + > + // > + // Send data to SMM. > + // > + Status =3D mMmCommunication2->Communicate (mMmCommunication2, > CommBuffer, CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data from SMM. > + // > + *VariablePayloadSize =3D SmmGetPayloadSize->VariablePayloadSize; > + > +Done: > + if (CommBuffer !=3D NULL) { > + FreePool (CommBuffer); > + } > + > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + This code gets information needed from SMM for runtime cache initializ= ation. > + > + @param[out] TotalHobStorageSize Output pointer for the total H= OB > storage size in bytes. > + @param[out] TotalNvStorageSize Output pointer for the total n= on- > volatile storage size in bytes. > + @param[out] TotalVolatileStorageSize Output pointer for the total v= olatile > storage size in bytes. > + @param[out] AuthenticatedVariableUsage Output pointer that indicates = if > authenticated variables are to be used. > + > + @retval EFI_SUCCESS Retrieved the size successfull= y. > + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter i= s > NULL. > + @retval EFI_OUT_OF_RESOURCES The memory resources needed fo= r a > CommBuffer are not available. > + @retval Others Could not retrieve the size su= ccessfully. > + > +**/ > +EFI_STATUS > +GetRuntimeCacheInfo ( > + OUT UINTN *TotalHobStorageSize, > + OUT UINTN *TotalNvStorageSize, > + OUT UINTN *TotalVolatileStorageSize, > + OUT BOOLEAN *AuthenticatedVariableUsage > + ) > +{ > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *SmmGetRuntimeCacheInfo; > + EFI_MM_COMMUNICATE_HEADER *SmmCommunicateHeader= ; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + UINTN CommSize; > + UINT8 *CommBuffer; > + > + SmmGetRuntimeCacheInfo =3D NULL; > + CommBuffer =3D mVariableBuffer; > + > + if ((TotalHobStorageSize =3D=3D NULL) || (TotalNvStorageSize =3D=3D NU= LL) || > (TotalVolatileStorageSize =3D=3D NULL) || (AuthenticatedVariableUsage =3D= =3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (CommBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + CommSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); > + ZeroMem (CommBuffer, CommSize); > + > + SmmCommunicateHeader =3D (EFI_MM_COMMUNICATE_HEADER > *)CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO); > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; > + SmmVariableFunctionHeader->Function =3D > SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO; > + SmmGetRuntimeCacheInfo =3D > (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO > *)SmmVariableFunctionHeader->Data; > + > + // > + // Send data to SMM. > + // > + Status =3D mMmCommunication2->Communicate (mMmCommunication2, > CommBuffer, CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <=3D SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status =3D EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status =3D SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Get data from SMM. > + // > + *TotalHobStorageSize =3D SmmGetRuntimeCacheInfo- > >TotalHobStorageSize; > + *TotalNvStorageSize =3D SmmGetRuntimeCacheInfo->TotalNvStorage= Size; > + *TotalVolatileStorageSize =3D SmmGetRuntimeCacheInfo- > >TotalVolatileStorageSize; > + *AuthenticatedVariableUsage =3D SmmGetRuntimeCacheInfo- > >AuthenticatedVariableUsage; > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Sends the runtime variable cache context information to SMM. > + > + @retval EFI_SUCCESS Retrieved the size successfully. > + @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL= . > + @retval EFI_OUT_OF_RESOURCES The memory resources needed for a > CommBuffer are not available. > + @retval Others Could not retrieve the size successf= ully.; > + > +**/ > +EFI_STATUS > +SendRuntimeVariableCacheContextToSmm ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *SmmRuntimeVarCacheContext; > + EFI_MM_COMMUNICATE_HEADER > *SmmCommunicateHeader; > + SMM_VARIABLE_COMMUNICATE_HEADER > *SmmVariableFunctionHeader; > + UINTN CommSize; > + UINT8 *CommBuffer; > + > + SmmRuntimeVarCacheContext =3D NULL; > + CommBuffer =3D mVariableBuffer; > + > + if (CommBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AcquireLockOnlyAtBootTime (&mVariableServicesLock); > + > + // > + // Init the communicate buffer. The buffer data size is: > + // SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + // > + CommSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + ZeroMem (CommBuffer, CommSize); > + > + SmmCommunicateHeader =3D (EFI_MM_COMMUNICATE_HEADER > *)CommBuffer; > + CopyGuid (&SmmCommunicateHeader->HeaderGuid, > &gEfiSmmVariableProtocolGuid); > + SmmCommunicateHeader->MessageLength =3D > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT); > + > + SmmVariableFunctionHeader =3D > (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; > + SmmVariableFunctionHeader->Function =3D > SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT; > + SmmRuntimeVarCacheContext =3D > (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT > *)SmmVariableFunctionHeader->Data; > + > + SmmRuntimeVarCacheContext->RuntimeHobCache =3D > mVariableRuntimeHobCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeVolatileCache =3D > mVariableRuntimeVolatileCacheBuffer; > + SmmRuntimeVarCacheContext->RuntimeNvCache =3D > mVariableRuntimeNvCacheBuffer; > + SmmRuntimeVarCacheContext->PendingUpdate =3D > &mVariableRuntimeCachePendingUpdate; > + SmmRuntimeVarCacheContext->ReadLock =3D > &mVariableRuntimeCacheReadLock; > + SmmRuntimeVarCacheContext->HobFlushComplete =3D > &mHobFlushComplete; > + > + // > + // Request to unblock this region to be accessible from inside MM > environment > + // These fields "should" be all on the same page, but just to be on th= e safe > side... > + // > + Status =3D MmUnblockMemoryRequest ( > + (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE > ((UINTN)SmmRuntimeVarCacheContext->PendingUpdate - EFI_PAGE_SIZE + 1, > EFI_PAGE_SIZE), > + EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCachePendingUpda= te)) > + ); > + if ((Status !=3D EFI_UNSUPPORTED) && EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D MmUnblockMemoryRequest ( > + (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE > ((UINTN)SmmRuntimeVarCacheContext->ReadLock - EFI_PAGE_SIZE + 1, > EFI_PAGE_SIZE), > + EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCacheReadLock)) > + ); > + if ((Status !=3D EFI_UNSUPPORTED) && EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D MmUnblockMemoryRequest ( > + (EFI_PHYSICAL_ADDRESS)ALIGN_VALUE > ((UINTN)SmmRuntimeVarCacheContext->HobFlushComplete - EFI_PAGE_SIZE + > 1, EFI_PAGE_SIZE), > + EFI_SIZE_TO_PAGES (sizeof (mHobFlushComplete)) > + ); > + if ((Status !=3D EFI_UNSUPPORTED) && EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Send data to SMM. > + // > + Status =3D mMmCommunication2->Communicate (mMmCommunication2, > CommBuffer, CommBuffer, &CommSize); > + ASSERT_EFI_ERROR (Status); > + if (CommSize <=3D SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) { > + Status =3D EFI_BAD_BUFFER_SIZE; > + goto Done; > + } > + > + Status =3D SmmVariableFunctionHeader->ReturnStatus; > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > +Done: > + ReleaseLockOnlyAtBootTime (&mVariableServicesLock); > + return Status; > +} > + > +/** > + Initialize variable service and install Variable Architectural protoco= l. > + > + @param[in] Event Event whose notification function is being invoked= . > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +SmmVariableReady ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; > + > + Status =3D gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (V= OID > **)&mSmmVariable); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + Status =3D gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NUL= L, > (VOID **)&mMmCommunication2); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Allocate memory for variable communicate buffer. > + // > + Status =3D GetVariablePayloadSize (&mVariableBufferPayloadSize); > + ASSERT_EFI_ERROR (Status); > + mVariableBufferSize =3D SMM_COMMUNICATE_HEADER_SIZE + > SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize; > + mVariableBuffer =3D AllocateRuntimePool (mVariableBufferSize); > + ASSERT (mVariableBuffer !=3D NULL); > + > + // > + // Save the buffer physical address used for SMM conmunication. > + // > + mVariableBufferPhysical =3D mVariableBuffer; > + > + if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n")); > + // > + // Allocate runtime variable cache memory buffers. > + // > + Status =3D GetRuntimeCacheInfo ( > + &mVariableRuntimeHobCacheBufferSize, > + &mVariableRuntimeNvCacheBufferSize, > + &mVariableRuntimeVolatileCacheBufferSize, > + &mVariableAuthFormat > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeHobCacheBuffer, > &mVariableRuntimeHobCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeNvCacheBuffer, > &mVariableRuntimeNvCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D InitVariableCache (&mVariableRuntimeVolatileCacheBu= ffer, > &mVariableRuntimeVolatileCacheBufferSize); > + if (!EFI_ERROR (Status)) { > + Status =3D SendRuntimeVariableCacheContextToSmm (); > + if (!EFI_ERROR (Status)) { > + SyncRuntimeCache (); > + } > + } > + } > + } > + > + if (EFI_ERROR (Status)) { > + mVariableRuntimeHobCacheBuffer =3D NULL; > + mVariableRuntimeNvCacheBuffer =3D NULL; > + mVariableRuntimeVolatileCacheBuffer =3D NULL; > + } > + } > + > + ASSERT_EFI_ERROR (Status); > + } else { > + DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"))= ; > + } > + > + gRT->GetVariable =3D RuntimeServiceGetVariable; > + gRT->GetNextVariableName =3D RuntimeServiceGetNextVariableName; > + gRT->SetVariable =3D RuntimeServiceSetVariable; > + gRT->QueryVariableInfo =3D RuntimeServiceQueryVariableInfo; > + > + // > + // Install the Variable Architectural Protocol on a new handle. > + // > + Status =3D gBS->InstallProtocolInterface ( > + &mHandle, > + &gEfiVariableArchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + mVariableLock.RequestToLock =3D VariableLockRequestToLock; > + Status =3D gBS->InstallMultipleProtocolInterfaces= ( > + &mHandle, > + &gEdkiiVariableLockProtocolGuid, > + &mVariableLock, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + mVarCheck.RegisterSetVariableCheckHandler =3D > VarCheckRegisterSetVariableCheckHandler; > + mVarCheck.VariablePropertySet =3D VarCheckVariableProperty= Set; > + mVarCheck.VariablePropertyGet =3D VarCheckVariableProperty= Get; > + Status =3D gBS->InstallMultipleProt= ocolInterfaces ( > + &mHandle, > + &gEdkiiVarCheckProt= ocolGuid, > + &mVarCheck, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + ContextIn.StructSize =3D sizeof (ContextIn); > + ContextIn.StructVersion =3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; > + > + ContextIn.FindVariableSmm =3D FindVariableInSmm; > + ContextIn.GetVariableInfo =3D GetVariableInfo; > + ContextIn.GetNextVariableInfo =3D GetNextVariableInfo; > + ContextIn.VariableServiceUser =3D FromRuntimeModule; > + ContextIn.MaxVariableSize =3D 0; > + ContextIn.UpdateVariableStore =3D NULL; > + ContextIn.UpdateVariable =3D NULL; > + > + Status =3D ProtectedVariableLibInitialize (&ContextIn); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "%a: %d ProtectedVariableLibInitialize() return status: %r\n", > + __FUNCTION__, > + __LINE__, > + Status > + )); > + } > + > + gBS->CloseEvent (Event); > +} > + > +/** > + SMM Non-Volatile variable write service is ready notify event handler. > + > + @param[in] Event Event whose notification function is being invoked= . > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +SmmVariableWriteReady ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + VOID *ProtocolOps; > + > + // > + // Check whether the protocol is installed or not. > + // > + Status =3D gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID > **)&ProtocolOps); > + if (EFI_ERROR (Status)) { > + return; > + } > + > + // > + // Some Secure Boot Policy Var (SecureBoot, etc) updates following oth= er > + // Secure Boot Policy Variable change. Record their initial value. > + // > + RecordSecureBootPolicyVarData (); > + > + Status =3D gBS->InstallProtocolInterface ( > + &mHandle, > + &gEfiVariableWriteArchProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + gBS->CloseEvent (Event); > +} > + > +/** > + Variable Driver main entry point. The Variable driver places the 4 EFI > + runtime services in the EFI System Table and installs arch protocols > + for variable read and write services being available. It also register= s > + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE > event. > + > + @param[in] ImageHandle The firmware allocated handle for the EFI im= age. > + @param[in] SystemTable A pointer to the EFI System Table. > + > + @retval EFI_SUCCESS Variable service successfully initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableSmmRuntimeInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + VOID *SmmVariableRegistration; > + VOID *SmmVariableWriteRegistration; > + EFI_EVENT OnReadyToBootEvent; > + EFI_EVENT ExitBootServiceEvent; > + EFI_EVENT LegacyBootEvent; > + > + EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY); > + > + // > + // Smm variable service is ready > + // > + EfiCreateProtocolNotifyEvent ( > + &gEfiSmmVariableProtocolGuid, > + TPL_CALLBACK, > + SmmVariableReady, > + NULL, > + &SmmVariableRegistration > + ); > + > + // > + // Smm Non-Volatile variable write service is ready > + // > + EfiCreateProtocolNotifyEvent ( > + &gSmmVariableWriteGuid, > + TPL_CALLBACK, > + SmmVariableWriteReady, > + NULL, > + &SmmVariableWriteRegistration > + ); > + > + // > + // Register the event to reclaim variable for OS usage. > + // > + EfiCreateEventReadyToBootEx ( > + TPL_NOTIFY, > + OnReadyToBoot, > + NULL, > + &OnReadyToBootEvent > + ); > + > + // > + // Register the event to inform SMM variable that it is at runtime. > + // > + gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + OnExitBootServices, > + NULL, > + &gEfiEventExitBootServicesGuid, > + &ExitBootServiceEvent > + ); > + > + // > + // Register the event to inform SMM variable that it is at runtime for= legacy > boot. > + // Reuse OnExitBootServices() here. > + // > + EfiCreateEventLegacyBootEx ( > + TPL_NOTIFY, > + OnExitBootServices, > + NULL, > + &LegacyBootEvent > + ); > + > + // > + // Register the event to convert the pointer for runtime. > + // > + gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + VariableAddressChangeEvent, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &mVirtualAddressChangeEvent > + ); > + > + // Initialize the VariablePolicy protocol and engine. > + VariablePolicySmmDxeMain (ImageHandle, SystemTable); > + > + return EFI_SUCCESS; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.c > new file mode 100644 > index 000000000000..943993eb6738 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableStandalon > eMm.c > @@ -0,0 +1,89 @@ > +/** @file > + > + Parts of the SMM/MM implementation that are specific to standalone MM > + > +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
> +Copyright (c) 2018, Linaro, Ltd. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Variable.h" > + > +/** > + This function checks if the buffer is valid per processor architecture= and > + does not overlap with SMRAM. > + > + @param Buffer The buffer start address to be checked. > + @param Length The buffer length to be checked. > + > + @retval TRUE This buffer is valid per processor architecture and does= not > + overlap with SMRAM. > + @retval FALSE This buffer is not valid per processor architecture or o= verlaps > + with SMRAM. > +**/ > +BOOLEAN > +VariableSmmIsBufferOutsideSmmValid ( > + IN EFI_PHYSICAL_ADDRESS Buffer, > + IN UINT64 Length > + ) > +{ > + return TRUE; > +} > + > +/** > + Notify the system that the SMM variable driver is ready. > +**/ > +VOID > +VariableNotifySmmReady ( > + VOID > + ) > +{ > +} > + > +/** > + Notify the system that the SMM variable write driver is ready. > +**/ > +VOID > +VariableNotifySmmWriteReady ( > + VOID > + ) > +{ > +} > + > +/** > + Variable service MM driver entry point. > + > + @param[in] ImageHandle A handle for the image that is initializing = this > + driver > + @param[in] MmSystemTable A pointer to the MM system table > + > + @retval EFI_SUCCESS Variable service successfully initialized. > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_MM_SYSTEM_TABLE *MmSystemTable > + ) > +{ > + return MmVariableServiceInitialize (); > +} > + > +/** > + Whether the TCG or TCG2 protocols are installed in the UEFI protocol > database. > + This information is used by the MorLock code to infer whether an exist= ing > + MOR variable is legitimate or not. > + > + @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI > + protocol database > + @retval FALSE Neither the TCG nor the TCG2 protocol is installed in th= e UEFI > + protocol database > +**/ > +BOOLEAN > +VariableHaveTcgProtocols ( > + VOID > + ) > +{ > + return FALSE; > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition > alMm.c > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition > alMm.c > new file mode 100644 > index 000000000000..0369c3cd01b1 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableTradition > alMm.c > @@ -0,0 +1,130 @@ > +/** @file > + > + Parts of the SMM/MM implementation that are specific to traditional MM > + > +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
> +Copyright (c) 2018, Linaro, Ltd. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include "Variable.h" > + > +/** > + This function checks if the buffer is valid per processor architecture= and > + does not overlap with SMRAM. > + > + @param Buffer The buffer start address to be checked. > + @param Length The buffer length to be checked. > + > + @retval TRUE This buffer is valid per processor architecture and does= not > + overlap with SMRAM. > + @retval FALSE This buffer is not valid per processor architecture or o= verlaps > + with SMRAM. > +**/ > +BOOLEAN > +VariableSmmIsBufferOutsideSmmValid ( > + IN EFI_PHYSICAL_ADDRESS Buffer, > + IN UINT64 Length > + ) > +{ > + return SmmIsBufferOutsideSmmValid (Buffer, Length); > +} > + > +/** > + Notify the system that the SMM variable driver is ready. > +**/ > +VOID > +VariableNotifySmmReady ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + > + Handle =3D NULL; > + Status =3D gBS->InstallProtocolInterface ( > + &Handle, > + &gEfiSmmVariableProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + Notify the system that the SMM variable write driver is ready. > +**/ > +VOID > +VariableNotifySmmWriteReady ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + > + Handle =3D NULL; > + Status =3D gBS->InstallProtocolInterface ( > + &Handle, > + &gSmmVariableWriteGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + Variable service MM driver entry point > + > + @param[in] ImageHandle A handle for the image that is initializing = this > + driver > + @param[in] SystemTable A pointer to the EFI system table > + > + @retval EFI_SUCCESS Variable service successfully initialized. > +**/ > +EFI_STATUS > +EFIAPI > +VariableServiceInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + return MmVariableServiceInitialize (); > +} > + > +/** > + Whether the TCG or TCG2 protocols are installed in the UEFI protocol > database. > + This information is used by the MorLock code to infer whether an exist= ing > + MOR variable is legitimate or not. > + > + @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI > + protocol database > + @retval FALSE Neither the TCG nor the TCG2 protocol is installed in th= e UEFI > + protocol database > +**/ > +BOOLEAN > +VariableHaveTcgProtocols ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + VOID *Interface; > + > + Status =3D gBS->LocateProtocol ( > + &gEfiTcg2ProtocolGuid, > + NULL, // Registration > + &Interface > + ); > + if (!EFI_ERROR (Status)) { > + return TRUE; > + } > + > + Status =3D gBS->LocateProtocol ( > + &gEfiTcgProtocolGuid, > + NULL, // Registration > + &Interface > + ); > + return !EFI_ERROR (Status); > +} > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.uni > new file mode 100644 > index 000000000000..227b8c6fad24 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xe.uni > @@ -0,0 +1,22 @@ > +// /** @file > +// Provides variable service. > +// > +// This module installs variable arch protocol and variable write arch p= rotocol > to provide > +// variable services: SetVariable, GetVariable, GetNextVariableName and > QueryVariableInfo. > +// > +// Caution: This module requires additional review when modified. > +// This driver will have external input - variable data. > +// This external input must be validated carefully to avoid security iss= ues such > as > +// buffer overflow or integer overflow. > +// > +// Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "Provides variab= le > service" > + > +#string STR_MODULE_DESCRIPTION #language en-US "This module > installs variable arch protocol and variable write arch protocol to provi= de > variable services: SetVariable, GetVariable, GetNextVariableName and > QueryVariableInfo. Caution: This module requires additional review when > modified. This driver will have external input - variable data. This exte= rnal input > must be validated carefully to avoid security issues such as buffer overf= low or > integer overflow." > + > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xeExtra.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xeExtra.uni > new file mode 100644 > index 000000000000..f0976418ff81 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableRuntimeD > xeExtra.uni > @@ -0,0 +1,14 @@ > +// /** @file > +// VariableRuntimeDxe Localized Strings and Content > +// > +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > +#string STR_PROPERTIES_MODULE_NAME > +#language en-US > +"VariableRuntimeDxe module" > + > + > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni > new file mode 100644 > index 000000000000..414c7cdc7c05 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmm.uni > @@ -0,0 +1,27 @@ > +// /** @file > +// Provides SMM variable service. > +// > +// This module installs SMM variable protocol into SMM protocol database= , > +// which can be used by SMM driver, and installs SMM variable protocol > +// into BS protocol database, which can be used to notify the SMM Runtim= e > +// Dxe driver that the SMM variable service is ready. > +// This module should be used with SMM Runtime DXE module together. The > +// SMM Runtime DXE module would install variable arch protocol and varia= ble > +// write arch protocol based on SMM variable module. > +// > +// Caution: This module requires additional review when modified. > +// This driver will have external input - variable data and communicate = buffer in > SMM mode. > +// This external input must be validated carefully to avoid security iss= ues such > as > +// buffer overflow or integer overflow. > +// > +// Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "Provides SMM > variable service" > + > +#string STR_MODULE_DESCRIPTION #language en-US "This module > installs SMM variable protocol into SMM protocol database, which can be u= sed > by SMM driver, and installs SMM variable protocol into BS protocol databa= se, > which can be used to notify the SMM Runtime DXE driver that the SMM varia= ble > service is ready. This module should be used with SMM Runtime DXE module > together. The SMM Runtime DXE module would install variable arch protocol > and variable write arch protocol based on SMM variable module. Caution: T= his > module requires additional review when modified. This driver will have ex= ternal > input - variable data and communicate buffer in SMM mode. This external i= nput > must be validated carefully to avoid security issues such as buffer overf= low or > integer overflow." > + > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr > a.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr > a.uni > new file mode 100644 > index 000000000000..f724209f3dc2 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmExtr > a.uni > @@ -0,0 +1,14 @@ > +// /** @file > +// VariableSmm Localized Strings and Content > +// > +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > +#string STR_PROPERTIES_MODULE_NAME > +#language en-US > +"VariableSmm module" > + > + > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.uni > new file mode 100644 > index 000000000000..9639f00077a0 > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxe.uni > @@ -0,0 +1,23 @@ > +// /** @file > +// This module is the Runtime DXE part correspond to SMM variable module= . > +// > +// It installs variable arch protocol and variable write arch protocol t= o provide > +// four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, > GetNextVariableName and QueryVariableInfo > +// and works with SMM variable module together. > +// > +// Caution: This module requires additional review when modified. > +// This driver will have external input - variable data. > +// This external input must be validated carefully to avoid security iss= ues such > as > +// buffer overflow or integer overflow. > +// > +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "The Runtime DXE > part corresponding to the SMM variable module" > + > +#string STR_MODULE_DESCRIPTION #language en-US "It installs var= iable > arch protocol and variable write arch protocol to provide four > EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and > QueryVariableInfo and works with SMM variable module together." > + > diff --git > a/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxeExtra.uni > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxeExtra.uni > new file mode 100644 > index 000000000000..bbabdf82736b > --- /dev/null > +++ > b/MdeModulePkg/Universal/Variable/Protected/RuntimeDxe/VariableSmmRunt > imeDxeExtra.uni > @@ -0,0 +1,14 @@ > +// /** @file > +// VariableSmmRuntimeDxe Localized Strings and Content > +// > +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. > +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > +#string STR_PROPERTIES_MODULE_NAME > +#language en-US > +"VariableSmmRuntimeDxe module" > + > + > -- > 2.35.1.windows.2