From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 1523774003B for ; Wed, 16 Aug 2023 02:46:20 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=cN9PlFb9TTAZwzgqPgihOnSXORo30Stp75TjazWu+aQ=; c=relaxed/simple; d=groups.io; h=ARC-Seal:ARC-Message-Signature:ARC-Authentication-Results:From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type:Content-Transfer-Encoding; s=20140610; t=1692153979; v=1; b=TPWxAyXX652PWDEQCUsK9Ub6+HsIZiP8tUDaHakP7kkibE0E0gGI78tFfMJfwBJPzGf0yJ6d LzUPkccJNQ8U8mHnuUYmzMMKzdXV8H1/Np2VzLlkj8GsiG2/UtGkmRWSkg/BpJ91Pg5oUMPiU6R SW7/97T4fuGE0yluKqybRLEA= X-Received: by 127.0.0.2 with SMTP id or2WYY7687511xiwJ0OUTxXV; Tue, 15 Aug 2023 19:46:19 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.93]) by mx.groups.io with SMTP id smtpd.web10.153010.1692153977118164598 for ; Tue, 15 Aug 2023 19:46:19 -0700 X-IronPort-AV: E=McAfee;i="6600,9927,10803"; a="369897092" X-IronPort-AV: E=Sophos;i="6.01,175,1684825200"; d="scan'208";a="369897092" X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2023 19:46:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10803"; a="857643419" X-IronPort-AV: E=Sophos;i="6.01,175,1684825200"; d="scan'208";a="857643419" X-Received: from orsmsx603.amr.corp.intel.com ([10.22.229.16]) by orsmga004.jf.intel.com with ESMTP; 15 Aug 2023 19:46:12 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) 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.2507.27; Tue, 15 Aug 2023 19:46:12 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Tue, 15 Aug 2023 19:46:12 -0700 X-Received: from orsedg603.ED.cps.intel.com (10.7.248.4) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27 via Frontend Transport; Tue, 15 Aug 2023 19:46:12 -0700 X-Received: from NAM12-MW2-obe.outbound.protection.outlook.com (104.47.66.49) by edgegateway.intel.com (134.134.137.100) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.27; Tue, 15 Aug 2023 19:46:11 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IjusvGMsnk1gDA2tBcIP88iPzs+Aevx5Qe22/2VS12nbH0Dt1EMmFN4nvafjyN9R/wdHmbCh1/nGxTUOss4qwSHfrwIUYJDKX5xbC1TUJI1aWFQ0H9Tuki/qhJ74P+/3z4qJk4/ZqZm2ZkPGFOe5pfG9FmtDB0d9bZePP7e32iF5nu5c9naW/7QiVpwchHfJAIZc6+Jx5SC3GcQDcWObHzfTr3De4rGtFfVZOMf/0OI67LPWWVnlfLQZazAz+2sei534l2I11xywQR2cPErhlH4GAiRDGQCVV6GCDkK+AML5UYwr7fqDVYAngeAb6kdnSpAbToKPBz9keF7Q2oO/jw== 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=m2Iy9n7hcLHYwdK0Jf9bQ1pgAvjA0BBq3WBR0O13vSw=; b=XIomydXLfWOYk11I50zug4SYZkN6baNBX7i6/ZAIS9GaAMSJTmlQCbxSaBrZ5qPMFHTg8Y357PDBnxVJmBdZhd+3YQ3hKzMsfYGCHMnIt4GLhpbsX0Le1Nig7b+FS7b5xqq6WeVIkGu0p/ewRPN+7SU3lljk49WJgNvCIegNyx6zAkO2WHMUetaQnNWn0Y9ntc1hw8vV9ADR0Jvbzt2zg+nGazwLLhwAWPE+t9ow7F03awoofIb1pFj684v9ZH59BSYwJ08AfeNbXu7dtzLEiR2zDwM4wAb5AU4JM++Ztp2rLmkUBxXF1O3o5EZqw39u+v8HugB2LoXtwxtwicd2Xg== 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 X-Received: from PH0PR11MB5626.namprd11.prod.outlook.com (2603:10b6:510:ee::15) by SA1PR11MB8447.namprd11.prod.outlook.com (2603:10b6:806:3ac::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6678.26; Wed, 16 Aug 2023 02:46:04 +0000 X-Received: from PH0PR11MB5626.namprd11.prod.outlook.com ([fe80::68a8:9cc5:ec4d:ca44]) by PH0PR11MB5626.namprd11.prod.outlook.com ([fe80::68a8:9cc5:ec4d:ca44%7]) with mapi id 15.20.6678.025; Wed, 16 Aug 2023 02:46:04 +0000 From: "Chuang, Rosen" To: "Kasbekar, Saloni" , "devel@edk2.groups.io" CC: "Chaganty, Rangasai V" , "Desimone, Nathaniel L" , "Oram, Isaac W" Subject: Re: [edk2-devel] [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Thread-Topic: [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Thread-Index: AQHZxvtTiFdEJNDcRUSQ6OIB/MLoAa/sSZEA Date: Wed, 16 Aug 2023 02:46:04 +0000 Message-ID: References: <09c9815c5f0382b638d24c777a4eb9105afc62e5.1691170619.git.saloni.kasbekar@intel.com> In-Reply-To: <09c9815c5f0382b638d24c777a4eb9105afc62e5.1691170619.git.saloni.kasbekar@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: PH0PR11MB5626:EE_|SA1PR11MB8447:EE_ x-ms-office365-filtering-correlation-id: 3e2286d8-c486-49b8-74a1-08db9e02ef26 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: 5UWKYp2WlKOZB8ay46jTDXipSrIgXGta/sIOsvyOo1AAWP11axuicOJX6xHWXWjpcRtQrAn5LN4mebsvCJN4Xw0xnODPD4hwKe2FYAUpwXw0Llcw6BBadM7Hz/1TwP23FRUXJGo8DrOvBae9F6VQKBdZ808T9dRWU9Kf5SXHrVM4bN66rRaNDm2taM81X2mO6hNRdjwKX/RG31q2glYHvleURXfdW0EHd/D9+r8y+0Mg0fO0oJXiDtH+yq32T4FtYQeKBfvfakEDDtqckG4ePU8lsfUp2Vc+wmKopdWNF/5/m65aOKJTrVYvWj4wTjal6j8F0n4CeaYiP9iVlayFV2b9YIphv3pb5clxHAQGmdRa8aKShHAJT4xn3fdM3Nmk3EmgQe794G2EGlRyxVahL2HJt/UhclD6iUTUP/sB4TJD/TIAtxmegmzIrEw1dnONiGifZThideC0n5OuMBBsUU9wG6GcN1Jbs2TAAE5fe7hI+65xqAc+fVWFyLP3ye85E9htgQ7ud2O4udZgpC/mu2D2KWuejm8E4EIRO+pKWIRAgjH138iUMUqO/rsI62IJ1UIJZtTqVniwkcP/mzExyI/xL2o72ax+1dYOQMyqyaBLyubxCb7zRFB7RFXuVfkqnuPTisf4eGPTMHNCo9EPwg== x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?3aW4tkRokxKe4dqzXTDcz0DMMMDo/ikXwI/4oYEM3AknEjn3Us1kP8+EbcIi?= =?us-ascii?Q?4Vvyj8pYzI2M2W6vU+Je2+dx8lTE7l02YOtbRNo+Nk0rgKBLfu00JIpI+oIr?= =?us-ascii?Q?u9M0R4pvVcP+xzDYlI6ZX0XVA2VBuJjHs/HgNJZriIWF46jaKz83HNudJdxn?= =?us-ascii?Q?gRvASlPf4oN7rMB+OMMCF7B7R6yPM82uNPJp76N2dJr48KXVzYucUnF5wjOx?= =?us-ascii?Q?x7hcduV4RZZLOibHlwNY/iwudq24odAj85OFqHiQJHJk23Rlzcats4K78eLy?= =?us-ascii?Q?YiJze8fIX6t7tbg374zvcZKGOQkM6bgES7jJ/Ox8hArGnju1SKqohQUthENZ?= =?us-ascii?Q?rzIcc7jevWPmdH01SfHOY2ff/HwDD9UJBzGcl6Kw40g2wzwbKk93nDG+KKeR?= =?us-ascii?Q?FWbOhm+bmfmIWbdeQFxntCD3dUq72x5y19YxJucxuxFXrGERTjUTUzB7FbF3?= =?us-ascii?Q?+tAPCSaCNZ82Dq6U4Av6m8EIjiQvOBrAakF+kRuMCb7HFtlV1pkobVAHcpPq?= =?us-ascii?Q?YVhqbAYDRVwVecLjlmrl46yGdcxpJ6VduaENUz4xhXnVrk7OvoVKxAN2uLo6?= =?us-ascii?Q?/czChYn+If38U/UEtE/6VSuywFmn55WKOInStgErZGOux8KIm/OCIJznvA53?= =?us-ascii?Q?zsFXYu3o8TkfnNBumGn3QQqkHRIWPAjt2DNyzIcl6DWpI8+LSV1Bro4JiltG?= =?us-ascii?Q?aLacKMPsc0XzKtr+0gi2igil6brD5u+rEXzEg9BTewxHSLM5z+aWN/+udml7?= =?us-ascii?Q?rBqCJH+Y0MjHxqmfzo99iAwZuBHA39V4CYQOVORUuD42vyEWGi9QhxTvr632?= =?us-ascii?Q?muX+AgQryQ2Yox2Iua9wFzVbdpeGWgECDOvgA8a5REK+L8eLEQ8xrKytN4pc?= =?us-ascii?Q?yq0UDP8y0JUkRYxPRjkAyE3PBjPRlUWjh4ut1rVz6gxSgnuJpJiZJu+hUyK3?= =?us-ascii?Q?Y1J9p3C9R4oLKhLXf9UnIk7j6u+5/CqD+BKj0sd2pBhgVGEltH2vhpR5zP94?= =?us-ascii?Q?OjAes1+IGCU4eZEXyJHRN9oPv/UUv1LxaQ+OTk0QufOXzWA9/tSEKLHq0tb9?= =?us-ascii?Q?stN1HSHMuGOgR5Ox6aPD8Kh+Q/PNYo+9a08y56BF1ofQUizqWwKU4bW6d0K8?= =?us-ascii?Q?21nxP0zkIKFBQKmrgfqzaOnBRo1A+UVc5yDydmXBw7ceG0rkWCYKhOUJMp4E?= =?us-ascii?Q?l/SIuPDFZFUxl60rAxAFV/ZX0wyX2tH56KJdvXoTvGZ3uER+3ScW9jhEOhO2?= =?us-ascii?Q?E/yyNrXQb2N2AgNoQHDDCKXobSRBq+sFzI+o328FkaBpU4YCZCKO6F0M+wLG?= =?us-ascii?Q?3wnMnIf1gfwmcMTu05W9mmNMCX7EMUVYzJMf04pPPd3+84FXlmfLlvRYkUgP?= =?us-ascii?Q?DthQQBtjV1MU54zfCFi1wQY2g/WVed2mmaAwGbqYzjDv1P3o+8s+0UbKD1Xb?= =?us-ascii?Q?6DL1Pg4CnwM8iTuS1vHg8NsmnNmX2LNVUoccLAzFv5OJb3SU2gss8GLrNapb?= =?us-ascii?Q?co4F/RKspP2NbETg2VHcN4eMRH7tqgqHnoGZI2H7zUU+4jeVyFMOUZFVk+yH?= =?us-ascii?Q?iiWCX4j2ykJ5PnrF59mJPf3FcdG8MOWS1hW8XcBv?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: PH0PR11MB5626.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3e2286d8-c486-49b8-74a1-08db9e02ef26 X-MS-Exchange-CrossTenant-originalarrivaltime: 16 Aug 2023 02:46:04.2347 (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: An1PojPE9KzBU+e2S8zLHv19k0O//C4w2iKgkDpCei6O3KxBHSiWsNjVMof49FUOBuY9UL10q9/BlwWXU1Jr3g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA1PR11MB8447 X-OriginatorOrg: intel.com Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,rosen.chuang@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: inewfW7rliQQTOMDD1U1Xjr4x7686176AA= Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=TPWxAyXX; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io; arc=reject ("signature check failed: fail, {[1] = sig:microsoft.com:reject}") Reviewed-by: Rosen Chuang < rosen.chuang@intel.com> -----Original Message----- From: Kasbekar, Saloni =20 Sent: Saturday, August 5, 2023 1:38 AM To: devel@edk2.groups.io Cc: Kasbekar, Saloni ; Chaganty, Rangasai V ; Desimone, Nathaniel L ; Oram, Isaac W ; Chuang, Rosen Subject: [PATCH v2 5/7] AlderlakeSiliconPkg/Pch: Add drivers Adds the following drivers: - PchSmiDispatcher - SmmControl Cc: Sai Chaganty Cc: Nate DeSimone Cc: Isaac Oram Cc: Rosen Chuang Signed-off-by: Saloni Kasbekar --- .../Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c | 1857 +++++++++++++++++ .../PchSmiDispatcher/Smm/PchSmiDispatcher.inf | 106 + .../Pch/PchSmiDispatcher/Smm/PchSmiHelper.h | 34 + .../Pch/PchSmiDispatcher/Smm/PchSmm.h | 1028 +++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmCore.c | 905 ++++++++ .../Pch/PchSmiDispatcher/Smm/PchSmmGpi.c | 255 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c | 332 +++ .../Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h | 163 ++ .../Smm/PchSmmPeriodicTimer.c | 670 ++++++ .../PchSmiDispatcher/Smm/PchSmmPowerButton.c | 77 + .../Pch/PchSmiDispatcher/Smm/PchSmmSw.c | 381 ++++ .../Pch/PchSmiDispatcher/Smm/PchSmmSx.c | 117 ++ .../Pch/PchSmiDispatcher/Smm/PchSmmUsb.c | 244 +++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c | 682 ++++++ .../Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h | 107 + .../Pch/PchSmiDispatcher/Smm/PcieSmmClient.c | 38 + .../Pch/PchSmiDispatcher/Smm/SmmGlobalsPch.c | 20 + .../Pch/SmmControl/RuntimeDxe/SmmControl.inf | 53 + .../SmmControl/RuntimeDxe/SmmControlDriver.c | 338 +++ .../SmmControl/RuntimeDxe/SmmControlDriver.h | 122 ++ 20 files changed, 7529 insertions(+) create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiDispatch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiDispatcher.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiHelper.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmm.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmCore.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmGpi.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmPeriodicTimer.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmPowerButton.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmSw.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmSx.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmmUsb.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchxSmmHelpers.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchxSmmHelpers.h create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PcieSmmClient.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/SmmGlobalsPch.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/Runtim= eDxe/SmmControl.inf create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/Runtim= eDxe/SmmControlDriver.c create mode 100644 Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/Runtim= eDxe/SmmControlDriver.h diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiDispatch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchSmiDispatch.c new file mode 100644 index 0000000000..637b9bb437 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp= atch.c @@ -0,0 +1,1857 @@ +/** @file + This function handle the register/unregister of PCH specific SMI events. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "PchSmiHelper.h" + + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source desc= ription + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + + if (SrcDesc =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + // + // Gather information about the registration request + // + Record.Signature =3D DATABASE_RECORD_SIGNATURE; + Record.PchSmiCallback =3D DispatchFunction; + Record.ProtocolType =3D PchSmiDispatchType; + Record.PchSmiType =3D PchSmiType; + + CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + Status =3D SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +// +// TCO_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts =3D= { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } + }, + NULL_BIT_DESC_INITIALIZER +}; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSourceAndBlock (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmClearSource (SrcDesc); + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source des= cription table + +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); + SrcDesc->En[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->En[1].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->Sts[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; + SrcDesc->PmcSmiSts.Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; +} + +// +// Mch srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_DMISMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of MCH event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiMchRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescMch, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiMchType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// TcoTimeout srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout= =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_TIMEOUT + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of TcoTimeout event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiTcoTimeoutRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescTcoTimeout, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiTcoTimeoutType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// OsTco srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco =3D = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_SW_TCO_SMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of OS TCO event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiOsTcoRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescOsTco, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiOsTcoType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// Nmi +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi =3D { + PCH_SMM_NO_FLAGS, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_CNT} + }, + S_TCO_IO_TCO1_CNT, + N_TCO_IO_TCO1_CNT_NMI2SMI_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NMI2SMI + } + }, + // + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS. + // So skip the top level status check and check the TCO1_STS direc= tly. + // + NULL_BIT_DESC_INITIALIZER +}; + +/** + The register function used to register SMI handler of NMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNmiRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescNmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNmiType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// IntruderDetect srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDe= t =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_CNT} + }, + S_TCO_IO_TCO2_CNT, + N_TCO_IO_TCO2_CNT_INTRD_SEL + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO2_STS} + }, + S_TCO_IO_TCO2_STS, + N_TCO_IO_TCO2_STS_INTRD_DET + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of Intruder Detect ev= ent. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiIntruderDetRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescIntruderDet, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiIntruderDetectType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// SpiBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_BLE + }, + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_SYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + Special handling for SPI Write Protect + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchTcoSpiWpClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 BiosControl; + UINT32 Timeout; + + SpiRegBase =3D SpiPciCfgBase (); + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS, + B_SPI_CFG_BC_SYNC_SS + ); + // + // Ensure the SYNC is cleared + // + Timeout =3D 1000; + do { + BiosControl =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC); + Timeout--; + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0)); + + // + // Any TCO-based status bits require special handling. + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the = TCO registers + // + PchSmmClearSource (&mDescSrcTcoSts); +} + +/** + Set SMI_EN_TCO to enable TCO SMI. +**/ +STATIC +VOID +PchSetSmiEnTco ( + VOID + ) +{ + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO); +} + +/** + The register function used to register SMI handler of BIOS write protect= event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiSpiBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescSpiBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiSpiBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSpiWpClearSource; + PchTcoSpiWpClearSource (NULL); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// LpcBiosWp srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_LPC_CFG_BC, + N_LPC_CFG_BC_LE + } + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_BIOSWR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of LPC BIOS write pro= tect event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiLpcBiosWpRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + if (IsEspiEnabled ()) { + // + // Status is D31F0's PCBC.BWPDS + // + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescLpcBiosWp, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiLpcBiosWpType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSource; + PchSmmClearSource (&Record->SrcDesc); + // + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. + // Only enable SMI_EN_TCO. + // + PchSetSmiEnTco (); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +// +// NEWCENTURY_STS bit that needs to be cleared +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury= =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + TCO_ADDR_TYPE, + {R_TCO_IO_TCO1_STS} + }, + S_TCO_IO_TCO1_STS, + N_TCO_IO_TCO1_STS_NEWCENTURY + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_TCO + } +}; + +/** + The register function used to register SMI handler of NEW CENTURY event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiNewCenturyRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescNewCentury, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchTcoSmiNewCenturyType, + DispatchHandle + ); + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; + PchSmmClearSource (&Record->SrcDesc); + PchSmmEnableSource (&Record->SrcDesc); + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EF= I_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NUL= L, 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchTcoSmiUnRegister ( + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + return EFI_SUCCESS; +} + +// +// Pme srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme =3D { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; + +/** + The register function used to register SMI handler of PME event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescPme, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPme); + PchSmmEnableSource (&mSrcDescPme); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0); + } + return Status; +} + +// +// PmeB0 srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 =3D = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_EN_127_96} + }, + S_ACPI_IO_GPE0_EN_127_96, + N_ACPI_IO_GPE0_EN_127_96_PME_B0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_GPE0_STS_127_96} + }, + S_ACPI_IO_GPE0_STS_127_96, + N_ACPI_IO_GPE0_STS_127_96_PME_B0 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPE0 + } +}; +/** + The register function used to register SMI handler of PME B0 event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiPmeB0Register ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescPmeB0, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiPmeB0Type, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescPmeB0); + PchSmmEnableSource (&mSrcDescPmeB0); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0); + } + return Status; +} + +// +// RtcAlarm srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = =3D { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_RTC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_RTC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of RTC alarm event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiRtcAlarmRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescRtcAlarm, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiRtcAlarmType, + DispatchHandle + ); + + PchSmmClearSource (&mSrcDescRtcAlarm); + PchSmmEnableSource (&mSrcDescRtcAlarm); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0); + } + return Status; +} + +// +// TmrOverflow srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflo= w =3D { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_TMROF + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_TMROF + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + The register function used to register SMI handler of Timer Overflow eve= nt. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiTmrOverflowRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescTmrOverflow, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchAcpiSmiTmrOverflowType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescTmrOverflow); + PchSmmEnableSource (&mSrcDescTmrOverflow); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (E= FI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NU= LL, 0); + } + + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchAcpiSmiUnRegister ( + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, = RecordToDelete->Callback, NULL, 0); + } + return Status; +} + +// +// SerialIrq srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = =3D { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SERIRQ + } +}; + +/** + The register function used to register SMI handler of Serial IRQ event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSerialIrqRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescSerialIrq, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSerialIrqType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSerialIrq); + PchSmmEnableSource (&mSrcDescSerialIrq); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_= SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL,= 0); + } + return Status; +} + +// +// McSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi =3D = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_MCSMI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_MCSMI + } +}; + +/** + The register function used to register SMI handler of MCSMI event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiMcSmiRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescMcSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiMcSmiType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescMcSmi); + PchSmmEnableSource (&mSrcDescMcSmi); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0); + } + return Status; +} + +// +// SmBus srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus =3D = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SMBUS + } +}; + +/** + The register function used to register SMI handler of SMBUS event. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSmbusRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescSmbus, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSmBusType, + DispatchHandle + ); + PchSmmClearSource (&mSrcDescSmbus); + PchSmmEnableSource (&mSrcDescSmbus); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0); + } + return Status; +} + +// +// SpiAsyncSmi srcdesc +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSmi =3D = { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASE_BWP + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + { 0xFFFFFFFF } // to be updated in PchSmiDispatchUpdateDescriptors + }, + S_SPI_CFG_BC, + N_SPI_CFG_BC_ASYNC_SS + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SPI + } +}; + +/** + Special handling for SPI Asynchronous SMI. + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done + transitions from 1 to 0 or when the SMI enable becomes false. + + @param[in] SrcDesc Not used +**/ +VOID +EFIAPI +PchSmiSpiAsyncClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINT64 SpiRegBase; + UINT32 SpiBar0; + + SpiRegBase =3D SpiPciCfgBase (); + SpiBar0 =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG= _BAR0_MASK); + if (SpiBar0 !=3D PCH_SPI_BASE_ADDRESS) { + // + // Temporary disable MSE, and override with SPI reserved MMIO address,= then enable MSE. + // + SpiBar0 =3D PCH_SPI_BASE_ADDRESS; + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMM= AND_MEMORY_SPACE); + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0); + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY= _SPACE); + } + + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE); +} + +/** + Special handling to enable SPI Asynchronous SMI +**/ +VOID +PchSmiSpiAsyncEnableSource ( + VOID + ) +{ + UINT64 SpiRegBase; + UINT32 Data32And; + UINT32 Data32Or; + + SpiRegBase =3D SpiPciCfgBase (); + Data32And =3D (UINT32) ~B_SPI_CFG_BC_SYNC_SS; + Data32Or =3D B_SPI_CFG_BC_ASE_BWP; + + PciSegmentAndThenOr32 ( + SpiRegBase + R_SPI_CFG_BC, + Data32And, + Data32Or + ); + S3BootScriptSavePciCfgReadWrite ( + S3BootScriptWidthUint32, + SpiRegBase + R_SPI_CFG_BC, + (VOID*) &Data32Or, + (VOID*) &Data32And + ); + + // + // Clear the source + // + PchSmiSpiAsyncClearSource (NULL); +} + +/** + The register function used to register SMI handler of SPI Asynchronous e= vent. + + @param[in] This The pointer to the protocol itself + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchSmiSpiAsyncRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D PchSmiRecordInsert ( + &mSrcDescSpiAsyncSmi, + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, + PchSmiSpiAsyncType, + DispatchHandle + ); + + if (!EFI_ERROR (Status)) { + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); + Record->ClearSource =3D PchSmiSpiAsyncClearSource; + PchSmiSpiAsyncClearSource (NULL); + PchSmiSpiAsyncEnableSource (); + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_S= MM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, = 0); + } + return Status; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered + @retval EFI_ACCESS_DENIED Return access denied since SPI ayn= c SMI handler is not able to disabled. +**/ +EFI_STATUS +EFIAPI +PchSmiUnRegister ( + IN PCH_SMI_DISPATCH_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *Record; + UINT64 SpiRegBase; + EFI_STATUS Status; + + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((Record->SrcDesc.En[0].Reg.Type =3D=3D PCIE_ADDR_TYPE) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev =3D=3D SpiDevNumber = ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc =3D=3D SpiFuncNumber= ()) && + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_BC)= && + (Record->SrcDesc.En[0].Bit =3D=3D N_SPI_CFG_BC_ASE_BWP)) { + SpiRegBase =3D SpiPciCfgBase (); + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) { + // + // SPI Asynchronous SMI cannot be disabled + // + return EFI_ACCESS_DENIED; + } + } + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Reco= rd->Callback, NULL, 0); + } + return Status; +} + + +/** + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance +**/ +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol =3D { + PCH_TCO_SMI_DISPATCH_REVISION, // Revision + PchTcoSmiUnRegister, // Unregister + PchTcoSmiMchRegister, // Mch + PchTcoSmiTcoTimeoutRegister, // TcoTimeout + PchTcoSmiOsTcoRegister, // OsTco + PchTcoSmiNmiRegister, // Nmi + PchTcoSmiIntruderDetRegister, // IntruderDectect + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp + PchTcoSmiNewCenturyRegister // NewCentury +}; + +/** + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance +**/ +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol =3D { + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision + PchAcpiSmiUnRegister, // Unregister + PchAcpiSmiPmeRegister, // Pme + PchAcpiSmiPmeB0Register, // PmeB0 + PchAcpiSmiRtcAlarmRegister, // RtcAlarm + PchAcpiSmiTmrOverflowRegister // TmrOverflow +}; + +/** + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance +**/ +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol =3D { + PCH_SMI_DISPATCH_REVISION, // Revision + PchSmiUnRegister, // Unregister + PchSmiSerialIrqRegister, // SerialIrq + PchSmiMcSmiRegister, // McSmi + PchSmiSmbusRegister, // SmBus + PchSmiSpiAsyncRegister // SpiAsync +}; + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI = types. + + @retval the result of protocol installatio= n +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + + Handle =3D NULL; + Status =3D gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchTcoSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchTcoSmiDispatchProtocol + ); + + Status =3D gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchAcpiSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchAcpiSmiDispatchProtocol + ); + Status =3D gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmiDispatchProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPchSmiDispatchProtocol + ); + + return Status; +} + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ) +{ + EFI_STATUS Status; + PCH_SMI_TYPES PchSmiType; + + PchSmiType =3D Record->PchSmiType; + Status =3D EFI_SUCCESS; + + switch (PchSmiType) { + case PchTcoSmiMchType: + case PchTcoSmiTcoTimeoutType: + case PchTcoSmiOsTcoType: + case PchTcoSmiNmiType: + case PchTcoSmiIntruderDetectType: + case PchTcoSmiSpiBiosWpType: + case PchTcoSmiLpcBiosWpType: + case PchTcoSmiNewCenturyType: + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HAN= DLE)&Record->Link); + break; + case PchPcieSmiRpHotplugType: + case PchPcieSmiRpLinkActiveType: + case PchPcieSmiRpLinkEqType: + break; + case PchAcpiSmiPmeType: + case PchAcpiSmiPmeB0Type: + case PchAcpiSmiRtcAlarmType: + case PchAcpiSmiTmrOverflowType: + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HA= NDLE)&Record->Link); + break; + case PchSmiSerialIrqType: + case PchSmiMcSmiType: + case PchSmiSmBusType: + case PchSmiSpiAsyncType: + case PchIoTrapSmiType: ///< internal type for IoTrap + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)= &Record->Link); + break; + default: + Status =3D EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + Performs update of SmiDispatch descriptors with values that have to be e= valuated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ) +{ + UINT32 SpiPcieAddr; + UINT32 LpcPcieAddr; + + SpiPcieAddr =3D ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (SpiDevNumber () << 19) | + (SpiFuncNumber () << 16) | + R_SPI_CFG_BC); + LpcPcieAddr =3D ((DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (LpcDevNumber () << 19) | + (LpcFuncNumber () << 16) | + R_LPC_CFG_BC); + // + // mSrcDescSpiBiosWp + // + mSrcDescSpiBiosWp.En[1].Reg.Data.raw =3D SpiPcieAddr; + mSrcDescSpiBiosWp.Sts[0].Reg.Data.raw =3D SpiPcieAddr; + + // + // mSrcDescLpcBiosWp + // + mSrcDescLpcBiosWp.En[1].Reg.Data.raw =3D LpcPcieAddr; + + // + // mSrcDescSpiAsyncSmi + // + mSrcDescSpiAsyncSmi.En[0].Reg.Data.raw =3D SpiPcieAddr; + mSrcDescSpiAsyncSmi.Sts[0].Reg.Data.raw =3D SpiPcieAddr; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiDispatcher.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/= Smm/PchSmiDispatcher.inf new file mode 100644 index 0000000000..7031b5193a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDisp= atcher.inf @@ -0,0 +1,106 @@ +## @file +# Component description file for the Pch SMI Dispatch Handlers module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D PchSmiDispatcher +FILE_GUID =3D B0D6ED53-B844-43f5-BD2F-61095264E77E +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_SMM_DRIVER +PI_SPECIFICATION_VERSION =3D 1.10 +ENTRY_POINT =3D InitializePchSmmDispatcher + + +[LibraryClasses] +UefiBootServicesTableLib +UefiDriverEntryPoint +IoLib +DebugLib +PcdLib +BaseLib +BaseMemoryLib +HobLib +DevicePathLib +PchCycleDecodingLib +PchPcieRpLib +PchPcrLib +SmmServicesTableLib +ReportStatusCodeLib +PerformanceLib +DxeServicesTableLib +GpioLib +GpioPrivateLib +EspiLib +S3BootScriptLib +ConfigBlockLib +PmcPrivateLib +PmcLib +SmiHandlerProfileLib +PchPciBdfLib +P2SbSidebandAccessLib +CpuPcieInfoFruLib + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Pcd] +# Progress Code for S3 Suspend start. +# PROGRESS_CODE_S3_SUSPEND_START =3D (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_S= PECIFIC | 0x00000000)) =3D 0x03078000 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart +# Progress Code for S3 Suspend end. +# PROGRESS_CODE_S3_SUSPEND_END =3D (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_S= PECIFIC | 0x00000001)) =3D 0x03078001 +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType + + +[Sources] +PchSmm.h +PchSmmCore.c +PchSmmHelpers.c +PchxSmmHelpers.c +SmmGlobalsPch.c +PchSmmUsb.c +PchSmmGpi.c +PchSmmPowerButton.c +PchSmmSw.c +PchSmmSx.c +PchSmmPeriodicTimer.c +PchSmiDispatch.c +PcieSmmClient.c + + +[Protocols] +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES +gEfiSmmBase2ProtocolGuid ## CONSUMES +gEfiSmmCpuProtocolGuid ## CONSUMES +gEfiSmmReadyToLockProtocolGuid ## CONSUMES +gPchTcoSmiDispatchProtocolGuid ## PRODUCES +gPchPcieSmiDispatchProtocolGuid ## PRODUCES +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES +gPchSmiDispatchProtocolGuid ## PRODUCES +gPchEspiSmiDispatchProtocolGuid ## PRODUCES +gPchSmmPeriodicTimerControlGuid ## PRODUCES + + +[Guids] + + +[Depex] +gEfiPciRootBridgeIoProtocolGuid AND +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure t= hat PCI MMIO resource has been prepared and available for this driver to al= locate. +gEfiSmmCpuProtocolGuid AND +gEfiSmmBase2ProtocolGuid + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmiHelper.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pc= hSmiHelper.h new file mode 100644 index 0000000000..5ec9455797 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp= er.h @@ -0,0 +1,34 @@ +/** @file + eSPI SMI Dispatch header + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCH_SMI_HELPER_H_ +#define _PCH_SMI_HELPER_H_ +#include + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port ph= ysical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device = number. + @param[out] RpFun Return corresponding root port functio= n number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ); + +/** + Performs update of SmiDispatch descriptors with values that have to be e= valuated during runtime. +**/ +VOID +PchSmiDispatchUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= Smm.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h new file mode 100644 index 0000000000..41969a0ec7 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h @@ -0,0 +1,1028 @@ +/** @file + Prototypes and defines for the PCH SMM Dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCH_SMM_H_ +#define _PCH_SMM_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 +#include +#include +#include + +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL + +extern BOOLEAN mReadyToLock; + +/// +/// Define an enumeration for all the supported protocols +/// +#define PCH_SMM_PROTOCOL_TYPE_MAX 6 + +typedef enum { + UsbType, + SxType, + SwType, + GpiType, + PowerButtonType, + PeriodicTimerType, + PchSmiDispatchType, + PchSmmProtocolTypeMax +} PCH_SMM_PROTOCOL_TYPE; + +/// +/// Define all the supported types of PCH SMI +/// +typedef enum { + PchTcoSmiMchType, + PchTcoSmiTcoTimeoutType, + PchTcoSmiOsTcoType, + PchTcoSmiNmiType, + PchTcoSmiIntruderDetectType, + PchTcoSmiSpiBiosWpType, + PchTcoSmiLpcBiosWpType, + PchTcoSmiNewCenturyType, + PchPcieSmiRpHotplugType, + PchPcieSmiRpLinkActiveType, + PchPcieSmiRpLinkEqType, + PchAcpiSmiPmeType, + PchAcpiSmiPmeB0Type, + PchAcpiSmiRtcAlarmType, + PchAcpiSmiTmrOverflowType, + PchEspiSmiEspiSlaveType, + PchSmiSerialIrqType, + PchSmiMcSmiType, + PchSmiSmBusType, + PchSmiSpiAsyncType, + PchIoTrapSmiType ///< internal SMI type +} PCH_SMI_TYPES; + +/// +/// Generic funciton pointer to cover all Pch SMI function pointer types +/// +typedef +VOID +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) ( + IN EFI_HANDLE DispatchHandle, + ... + ); + + +/// +/// SPECIFYING A REGISTER +/// We want a general way of referring to addresses. For this case, we'll= only +/// need addresses in the ACPI table (and the TCO entries within the ACPI = table). +/// However, it's interesting to consider what it would take to support ot= her types +/// of addresses. To address Will's concern, I think it prudent to accomm= odate it +/// early on in the design. +/// +/// Addresses we need to consider: +/// +/// Type: Required: +/// I/O Yes +/// ACPI (special case of I/O) Only if we want to +/// TCO (special case of I/O) Only if we want to +/// GPIO (special case of MMIO) Only if we want to +/// Memory (or Memory Mapped I/O) Only if we want to +/// PCIE Yes, for BiosWp +/// +typedef enum { + /// + /// IO_ADDR_TYPE, /// unimplemented + /// + ACPI_ADDR_TYPE, + TCO_ADDR_TYPE, + /// + /// MEMORY_ADDR_TYPE, /// unimplemented + /// + GPIO_ADDR_TYPE, + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCIE_ADDR_TYPE, + PCR_ADDR_TYPE, + NUM_ADDR_TYPES, ///< count of items in this enum + PCH_SMM_ADDR_TYPE_NULL =3D -1 ///< sentinel to indicate NULL or = to signal end of arrays +} ADDR_TYPE; + +// +// Assumption: 32-bits -- enum's evaluate to integer +// Assumption: This code will only run on IA-32. Justification: IA-64 doe= sn't have SMIs. +// We don't have to worry about 64-bit addresses. +// Typedef the size of addresses in case the numbers I'm using are wrong o= r in case +// this changes. This is a good idea because PCI_ADDR will change, for ex= ample, when +// we add support for PciExpress. +// +typedef UINT16 IO_ADDR; +typedef IO_ADDR ACPI_ADDR; ///< can omit +typedef IO_ADDR TCO_ADDR; ///< can omit +typedef UINTN MEM_ADDR; +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; +typedef MEM_ADDR *GPIO_ADDR; +typedef union { + UINT32 Raw; + struct { + UINT32 Reg: 16; + UINT32 Fnc: 3; + UINT32 Dev: 5; + UINT32 Bus: 8; + } Fields; +} PCIE_ADDR; + +typedef union { + UINT32 Raw; + struct { + UINT16 Offset; + UINT8 Pid; + UINT8 Base; + } Fields; +} PCR_ADDR; + +typedef struct { + ADDR_TYPE Type; + union { + /// + /// used to initialize during declaration/definition + /// + UINT32 raw; + + /// + /// used to access useful data + /// + IO_ADDR io; + ACPI_ADDR acpi; + TCO_ADDR tco; + GPIO_ADDR gpio; + MEM_ADDR mem; + MEMORY_MAPPED_IO_ADDRESS Mmio; + PCIE_ADDR pcie; + PCR_ADDR Pcr; + + } Data; + +} PCH_SMM_ADDRESS; + +/// +/// SPECIFYING BITS WITHIN A REGISTER +/// Here's a struct that helps us specify a source or enable bit. +/// +typedef struct { + PCH_SMM_ADDRESS Reg; + UINT8 SizeInBytes; ///< of the register + UINT8 Bit; +} PCH_SMM_BIT_DESC; + +// +// Sometimes, we'll have bit descriptions that are unused. It'd be great = to have a +// way to easily identify them: +// +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type =3D=3D PCH_SMM_ADD= R_TYPE_NULL) ///< "returns" true when BitDesc is NULL +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =3D PCH_SMM_ADDR_T= YPE_NULL) ///< will "return" an integer w/ value of 0 +#define NULL_BIT_DESC_INITIALIZER \ + { \ + { \ + PCH_SMM_ADDR_TYPE_NULL, \ + { \ + 0 \ + } \ + }, \ + 0, 0 \ + } +// +// I'd like a type to specify the callback's Sts & En bits because they'll +// be commonly used together: +// +#define NUM_EN_BITS 2 +#define NUM_STS_BITS 1 + +// +// Flags +// +typedef UINT8 PCH_SMM_SOURCE_FLAGS; + +// +// Flags required to describe the event source +// +#define PCH_SMM_NO_FLAGS 0 +#define PCH_SMM_SCI_EN_DEPENDENT 1 + +typedef struct { + PCH_SMM_SOURCE_FLAGS Flags; + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable bit(= s) for the SMI event + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the secondary s= tatus bit for the SMI event. Might be the same as TopLevelSmi + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top leve= l status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS +} PCH_SMM_SOURCE_DESC; + +/// +/// Used to initialize null source descriptor +/// +#define NULL_SOURCE_DESC_INITIALIZER \ + { \ + PCH_SMM_NO_FLAGS, \ + { \ + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + NULL_BIT_DESC_INITIALIZER \ + }, \ + NULL_BIT_DESC_INITIALIZER \ + } + +/// +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool +/// +typedef struct { + PCH_SMI_TYPES PchSmiType; + UINTN RpIndex; +} PCH_SMM_PCIE_REGISTER_CONTEXT; + +/// +/// CHILD CONTEXTS +/// To keep consistent w/ the architecture, we'll need to provide the cont= ext +/// to the child when we call its callback function. After talking with W= ill, +/// we agreed that we'll need functions to "dig" the context out of the ha= rdware +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compa= re those +/// contexts to prevent unnecessary dispatches. I'd like a general type f= or these +/// "GetContext" functions, so I'll need a union of all the protocol conte= xts for +/// our internal use: +/// +typedef union { + // + // (in no particular order) + // + EFI_SMM_SX_REGISTER_CONTEXT Sx; + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; + EFI_SMM_SW_REGISTER_CONTEXT Sw; + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; + EFI_SMM_USB_REGISTER_CONTEXT Usb; + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie; +} PCH_SMM_CONTEXT; + +/// +/// Misc data for PchDispatcher usage. +/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIO= DIC_TIMER_REGISTER_CONTEXT of EDKII, +/// and PchDispatcher needs it for every record. Thus move it here to supp= ort ElapsedTime. +/// +typedef struct { + UINTN ElapsedTime; + /// + /// A switch to control periodic timer SMI enabling + /// + BOOLEAN TimerSmiEnabled; +} PCH_SMM_MISC_DATA; + +// +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes +// +typedef struct _DATABASE_RECORD DATABASE_RECORD; + +/// +/// Assumption: the GET_CONTEXT function will be as small and simple as po= ssible. +/// Assumption: We don't need to pass in an enumeration for the protocol b= ecause each +/// GET_CONTEXT function is written for only one protocol. +/// We also need a function to compare contexts to see if the child should= be dispatched +/// In addition, we need a function to acquire CommBuffer and CommBufferSi= ze for +/// dispatch callback function of EDKII native support. +/// +typedef +VOID +(EFIAPI *GET_CONTEXT) ( + IN DATABASE_RECORD * Record, + OUT PCH_SMM_CONTEXT * Context + ); + +typedef +BOOLEAN +(EFIAPI *CMP_CONTEXT) ( + IN PCH_SMM_CONTEXT * Context1, + IN PCH_SMM_CONTEXT * Context2 + ); + +typedef +VOID +(EFIAPI *GET_COMMBUFFER) ( + IN DATABASE_RECORD * Record, + OUT VOID **CommBuffer, + OUT UINTN * CommBufferSize + ); + +/// +/// Finally, every protocol will require a "Get Context" and "Compare Cont= ext" call, so +/// we may as well wrap that up in a table, too. +/// +typedef struct { + GET_CONTEXT GetContext; + CMP_CONTEXT CmpContext; + GET_COMMBUFFER GetCommBuffer; +} CONTEXT_FUNCTIONS; + +extern CONTEXT_FUNCTIONS ContextFunctions[PCH_SMM_PROTOCOL_TYPE_M= AX]; + +/// +/// MAPPING CONTEXT TO BIT DESCRIPTIONS +/// I'd like to have a general approach to mapping contexts to bit descrip= tions. +/// Sometimes, we'll find that we can use table lookups or constant assign= ments; +/// other times, we'll find that we'll need to use a function to perform t= he mapping. +/// If we define a macro to mask that process, we'll never have to change = the code. +/// I don't know if this is desirable or not -- if it isn't, then we can g= et rid +/// of the macros and just use function calls or variable assignments. Do= esn't matter +/// to me. +/// Mapping complex contexts requires a function +/// + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must b= e USB. + @param[out] SrcDesc The source description that corresponds = to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context inst= ances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchCon= text, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +// +// Mapping simple contexts can be done by assignment or lookup table +// +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc; +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury; +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate; + +/// +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. +/// +#define MAXIMUM_SWI_VALUE 0xFF +/// +/// Open: Need to make sure this kind of type cast will actually work. +/// May need an intermediate form w/ two VOID* arguments. I'll figure +/// that out when I start compiling. +/// +typedef +VOID +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( + CONST PCH_SMM_SOURCE_DESC * SrcDesc + ); + +/// +/// "DATABASE" RECORD +/// Linked list data structures +/// +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') + +struct _DATABASE_RECORD { + UINT32 Signature; + LIST_ENTRY Link; + BOOLEAN Processed; + /// + /// Status and Enable bit description + /// + PCH_SMM_SOURCE_DESC SrcDesc; + + /// + /// Callback function + /// + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; + PCH_SMM_CONTEXT ChildContext; + UINTN ContextSize; + + /// + /// Special handling hooks -- init them to NULL if unused/unneeded + /// + PCH_SMM_CLEAR_SOURCE ClearSource; + + /// + /// Functions required to make callback code general + /// + CONTEXT_FUNCTIONS ContextFunctions; + + /// + /// The protocol that this record dispatches + /// + PCH_SMM_PROTOCOL_TYPE ProtocolType; + + /// + /// Misc data for private usage + /// + PCH_SMM_MISC_DATA MiscData; + + /// + /// PCH SMI callback function + /// + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback; + /// + /// Indicate the PCH SMI types. + /// + PCH_SMI_TYPES PchSmiType; +}; + +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, = Link, DATABASE_RECORD_SIGNATURE) +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, DATABASE_= RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) + +/// +/// HOOKING INTO THE ARCHITECTURE +/// +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( + IN VOID **This, + IN VOID *DispatchFunction, + IN VOID *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( + IN VOID **This, + IN EFI_HANDLE DispatchHandle + ); + +/// +/// Define a memory "stamp" equivalent in size and function to most of the= protocols +/// +typedef struct { + PCH_SMM_GENERIC_REGISTER Register; + PCH_SMM_GENERIC_UNREGISTER Unregister; + UINTN Extra1; + UINTN Extra2; ///< may not need this one +} PCH_SMM_GENERIC_PROTOCOL; + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance. + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's conte= xt. + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing + with the parent SMM driver, will be the = address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create databas= e record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfu= lly + registered and the SMI source has been e= nabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + + +/** + Unregister a child SMI source dispatch function with a parent SMM driver= . + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance. + @param[in] DispatchHandle Handle of dispatch function to deregiste= r. + + @retval EFI_SUCCESS The dispatch function has been successfu= lly + unregistered and the SMI source has been= disabled + if there are no other registered child d= ispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + +typedef union { + PCH_SMM_GENERIC_PROTOCOL Generic; + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; +} PCH_SMM_PROTOCOL; + +/// +/// Define a structure to help us identify the generic protocol +/// +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') + +typedef struct { + UINTN Signature; + + PCH_SMM_PROTOCOL_TYPE Type; + EFI_GUID *Guid; + PCH_SMM_PROTOCOL Protocols; +} PCH_SMM_QUALIFIED_PROTOCOL; + +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ + CR ( \ + _generic, \ + PCH_SMM_QUALIFIED_PROTOCOL, \ + Protocols, \ + PROTOCOL_SIGNATURE \ + ) + +/// +/// Create private data for the protocols that we'll publish +/// +typedef struct { + LIST_ENTRY CallbackDataBase; + EFI_HANDLE SmiHandle; + EFI_HANDLE InstallMultProtHandle; + PCH_SMM_QUALIFIED_PROTOCOL Protocols[PCH_SMM_PROTOCOL_TYPE_MAX]; +} PRIVATE_DATA; + +extern PRIVATE_DATA mPrivateData; +extern UINT16 mAcpiBaseAddr; +extern UINT16 mTcoBaseAddr; + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits t= o be filled +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Register a child SMI source dispatch function for the specified software= SMI. + + This service registers a function (DispatchFunction) which will be calle= d when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On r= eturn, + DispatchHandle contains a unique handle which may be used later to unreg= ister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PRO= TOCOL instance. + @param[in] DispatchFunction Function to register for handler when t= he specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's cont= ext. + The caller fills this context in before= calling + the register function to indicate to th= e register + function which Software SMI input value= the + dispatch function should be invoked for= . + @param[out] DispatchHandle Handle generated by the dispatcher to t= rack the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successful= ly + registered and the SMI source has been en= abled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SM= I source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI in= put value + is not within a valid range or is already= in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be = assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function for the specified softwa= re SMI. + + This service removes the handler associated with DispatchHandle so that = it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister= . + + @retval EFI_SUCCESS The dispatch function has been successful= ly unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ); + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer = 1 + @param[in] Context2 Context 2 that includes Periodic Timer = 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structur= e +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ); + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will = be updated with the current power button status. +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button sta= tus 1 + @param[in] Context2 Context 2 that includes Power Button sta= tus 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + This function is responsible for calculating and enabling any timers tha= t are required + to dispatch messages to children. The SrcDesc argument isn't acutally us= ed. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce. +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + This services returns the next SMI tick period that is supported by the = chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DI= SPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter S= MI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid= . +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ); + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed su= ccessfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ); + +/** + Install protocols of PCH specifics SMI types, including + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI = types. + + @retval the result of protocol installatio= n +**/ +EFI_STATUS +InstallPchSmiDispatchProtocols ( + VOID + ); + +/** + The function to dispatch all callback function of PCH SMI types. + + @retval EFI_SUCCESS Function successfully completed + @retval EFI_UNSUPPORTED no +**/ +EFI_STATUS +PchSmiTypeCallbackDispatcher ( + IN DATABASE_RECORD *Record + ); + +/** + The register function used to register SMI handler of IoTrap event. + This is internal function and only used by Iotrap module. + + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[in] IoTrapIndex Index number of IOTRAP register + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. +**/ +EFI_STATUS +PchInternalIoTrapSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN UINTN IoTrapIndex, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalIoTrapSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + Register an eSPI SMI handler based on the type + + @param[in] DispatchFunction Callback in an event of eSPI SMI + @param[in] PchSmiTypes The eSPI type published by PchSmiDis= patch + @param[out] DispatchHandle The callback handle + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descripti= on + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database r= ecord + @retval EFI_SUCCESS Registration is successful. +**/ +EFI_STATUS +PchInternalEspiSmiRegister ( + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, + IN PCH_SMI_TYPES PchSmiTypes, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister an eSPI SMI handler + + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchInternalEspiSmiUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + The internal function used to create and insert a database record + for SMI record of Pch Smi types. + + @param[in] SrcDesc The pointer to the SMI source desc= ription + @param[in] DispatchFunction Pointer to dispatch function to be= invoked for this SMI source + @param[in] PchSmiType Specific SMI type of PCH SMI + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. +**/ +EFI_STATUS +PchSmiRecordInsert ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, + IN PCH_SMI_TYPES PchSmiType, + OUT EFI_HANDLE *DispatchHandle + ); + +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq; +extern PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp; + +/** + Clear the TCO SMI status bit and block after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table + +**/ +VOID +EFIAPI +PchTcoSmiClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Clear the TCO SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table + +**/ +VOID +EFIAPI +PchTcoSmiClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Initialize Source descriptor structure + + @param[in] SrcDesc Pointer to the PCH SMI source desc= ription table +**/ +VOID +EFIAPI +NullInitSourceDesc ( + PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROT= OCOL instance. + @param[in] DispatchFunction Function to register for handler when the= specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's contex= t. + The caller fills this context in before c= alling + the register function to indicate to the = register + function the GPI(s) for which the dispatc= h function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to tra= ck the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successful= ly + registered and the SMI source has been en= abled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input= value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PRO= TOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregiste= r. + + @retval EFI_SUCCESS The dispatch function has been successfu= lly + unregistered and the SMI source has been= disabled + if there are no other registered child d= ispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmCore.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchS= mmCore.c new file mode 100644 index 0000000000..cb889b5ce3 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore= .c @@ -0,0 +1,905 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include "PchSmiHelper.h" +#include +#include +#include +#include +#include + +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32 (PcdProgressCodeS3Suspend= Start) +// +// MODULE / GLOBAL DATA +// +// Module variables used by the both the main dispatcher and the source di= spatchers +// Declared in PchSmm.h +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfRootPorts; + +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData =3D { + { + NULL, + NULL + }, // CallbackDataBase linked list he= ad + NULL, // EFI handle returned when callin= g InstallMultipleProtocolInterfaces + NULL, // + { // protocol arrays + // + // elements within the array + // + { + PROTOCOL_SIGNATURE, + UsbType, + &gEfiSmmUsbDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SxType, + &gEfiSmmSxDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + SwType, + &gEfiSmmSwDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister, + (UINTN) MAXIMUM_SWI_VALUE + }} + }, + { + PROTOCOL_SIGNATURE, + GpiType, + &gEfiSmmGpiDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister, + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS + }} + }, + { + PROTOCOL_SIGNATURE, + PowerButtonType, + &gEfiSmmPowerButtonDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister + }} + }, + { + PROTOCOL_SIGNATURE, + PeriodicTimerType, + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, + {{ + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister, + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval + }} + }, + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS mContextFunctions[PCH_= SMM_PROTOCOL_TYPE_MAX] =3D { + { + NULL, + NULL, + NULL + }, + { + SxGetContext, + SxCmpContext, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + PowerButtonGetContext, + PowerButtonCmpContext, + NULL + }, + { + PeriodicTimerGetContext, + PeriodicTimerCmpContext, + PeriodicTimerGetCommBuffer + }, +}; + +// +// PROTOTYPES +// +// Functions use only in this file +// +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, OPTIONAL + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ); + +// +// FUNCTIONS +// +/** + SMM ready to lock 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 SmmReadyToLockCallback runs successfully + +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockCallback ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + mReadyToLock =3D TRUE; + + return EFI_SUCCESS; +} + +/** + PchSmiDispatcher SMM Module Entry Point\n + - Introduction\n + The PchSmiDispatcher module is an SMM driver which provides SMI handl= er registration + services for PCH generated SMIs. + + - Details\n + This module provides SMI handler registration servicies for PCH SMIs. + NOTE: All the register/unregister functions will be locked after SMM r= eady to boot signal event. + Please make sure no handler is installed after that. + + - @pre + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specificat= ion + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + - Documented in the UEFI 2.0 Specification and above + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + - This is to ensure that PCI MMIO and IO resource has been prepared = and available for this driver to allocate. + - EFI_SMM_CPU_PROTOCOL + + - @result + The PchSmiDispatcher driver produces: + - EFI_SMM_USB_DISPATCH2_PROTOCOL + - EFI_SMM_SX_DISPATCH2_PROTOCOL + - EFI_SMM_SW_DISPATCH2_PROTOCOL + - EFI_SMM_GPI_DISPATCH2_PROTOCOL + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROT= OCOL @endlink + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL= @endlink + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @= endlink + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL= @endlink + - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink + + @param[in] ImageHandle Pointer to the loaded image protocol for= this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS PchSmmDispatcher Initialization complete= d. +**/ +EFI_STATUS +EFIAPI +InitializePchSmmDispatcher ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *SmmReadyToLockRegistration; + + mS3SusStart =3D FALSE; + + PchSmiDispatchUpdateDescriptors (); + + // + // Access ACPI Base Addresses Register + // + mAcpiBaseAddr =3D PmcGetAcpiBase (); + ASSERT (mAcpiBaseAddr !=3D 0); + + // + // Access TCO Base Addresses Register + // + PchTcoBaseGet (&mTcoBaseAddr); + ASSERT (mTcoBaseAddr !=3D 0); + + mNumOfRootPorts =3D GetPchMaxPciePortNum (); + + // + // Register a callback function to handle subsequent SMIs. This callbac= k + // will be called by SmmCoreDispatcher. + // + Status =3D gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPriv= ateData.SmiHandle); + ASSERT_EFI_ERROR (Status); + // + // Initialize Callback DataBase + // + InitializeListHead (&mPrivateData.CallbackDataBase); + + // + // Enable SMIs on the PCH now that we have a callback + // + PchSmmInitHardware (); + + // + // Install and initialize all the needed protocols + // + PchSwDispatchInit (); + PchSmmPublishDispatchProtocols (); + InstallPchSmiDispatchProtocols (); + InstallPchSmmPeriodicTimerControlProtocol (mPrivateData.InstallMultProtH= andle); + + // + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function. + // + Status =3D gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + SmmReadyToLockCallback, + &SmmReadyToLockRegistration + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + The internal function used to create and insert a database record + + @param[in] InsertRecord Record to insert to database. + @param[out] DispatchHandle Handle of dispatch function to reg= ister. + + @retval EFI_INVALID_PARAMETER Error with NULL SMI source descrip= tion + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database= record + @retval EFI_SUCCESS The database record is created suc= cessfully. +**/ +EFI_STATUS +SmmCoreInsertRecord ( + IN DATABASE_RECORD *NewRecord, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + + if ((NewRecord =3D=3D NULL) || + (NewRecord->Signature !=3D DATABASE_RECORD_SIGNATURE)) + { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATAB= ASE_RECORD), (VOID **) &Record); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD)); + + // + // After ensuring the source of event is not null, we will insert the re= cord into the database + // + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver + + @param[in] This Protocol instance pointer. + @param[in] DispatchHandle Handle of dispatch function to der= egister. + + @retval EFI_SUCCESS The dispatch function has been suc= cessfully + unregistered and the SMI source ha= s been disabled + if there are no other registered c= hild dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. + @retval EFI_ACCESS_DENIED Return access denied if the SmmRea= dyToLock event has been triggered +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + DATABASE_RECORD *RecordToDelete; + EFI_STATUS Status; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); + if (!EFI_ERROR (Status)) { + SmiHandlerProfileUnregisterHandler ( + Qualified->Guid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + } + return Status; +} + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance. + @param[in] DispatchFunction Pointer to dispatch function to be invok= ed for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's conte= xt. + @param[out] DispatchHandle Handle of dispatch function, for when in= terfacing + with the parent SMM driver, will be the = address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create databas= e record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfu= lly + registered and the SMI source has been e= nabled. +**/ +EFI_STATUS +EFIAPI +PchPiSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + PCH_SMM_SOURCE_DESC NullSourceDesc; + + // + // Initialize NullSourceDesc + // + NullInitSourceDesc (&NullSourceDesc); + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event ha= s been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback =3D DispatchFunction; + + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); + + Record.ProtocolType =3D Qualified->Type; + + Record.ContextFunctions =3D mContextFunctions[Qualified->Type]; + // + // Perform linked list housekeeping + // + Record.Signature =3D DATABASE_RECORD_SIGNATURE; + + switch (Qualified->Type) { + // + // By the end of this switch statement, we'll know the + // source description the child is registering for + // + case UsbType: + Record.ContextSize =3D sizeof (EFI_SMM_USB_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type + // + if ((Record.ChildContext.Usb.Type < UsbLegacy) || (Record.ChildConte= xt.Usb.Type > UsbWake)) { + return EFI_INVALID_PARAMETER; + } + + PchSmmUsbUpdateDescriptors (); + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.ClearSource =3D NULL; + // + // use default clear source function + // + break; + + case SxType: + Record.ContextSize =3D sizeof (EFI_SMM_SX_REGISTER_CONTEXT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Type and Phase + // + if ((Record.ChildContext.Sx.Type < SxS0) || + (Record.ChildContext.Sx.Type >=3D EfiMaximumSleepType) || + (Record.ChildContext.Sx.Phase < SxEntry) || + (Record.ChildContext.Sx.Phase >=3D EfiMaximumPhase) + ) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof (PCH_SMM_SOURCE_DES= C)); + Record.ClearSource =3D NULL; + // + // use default clear source function + // + break; + + case PowerButtonType: + Record.ContextSize =3D sizeof (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT= ); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of Context Phase + // + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) || + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit)) + { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof (PCH_SMM_S= OURCE_DESC)); + Record.ClearSource =3D NULL; + // + // use default clear source function + // + break; + + case PeriodicTimerType: + Record.ContextSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTE= XT); + CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize); + // + // Check the validity of timer value + // + if (DispatchContext->PeriodicTimer.SmiTickInterval <=3D 0) { + return EFI_INVALID_PARAMETER; + } + + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc); + Record.MiscData.TimerSmiEnabled =3D TRUE; + Record.ClearSource =3D PchSmmPeriodicTimerClearSource; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) { + return EFI_INVALID_PARAMETER; + } + + // + // After ensuring the source of event is not null, we will insert the re= cord into the database + // Child's handle will be the address linked list link in the record + // + Status =3D SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + if (Record.ClearSource =3D=3D NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + PchSmmClearSource (&Record.SrcDesc); + } else { + // + // This source requires special handling to clear + // + Record.ClearSource (&Record.SrcDesc); + } + + PchSmmEnableSource (&Record.SrcDesc); + SmiHandlerProfileRegisterHandler ( + Qualified->Guid, + DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + DispatchContext, + Record.ContextSize + ); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver= . + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL = instance. + @param[in] DispatchHandle Handle of dispatch function to deregiste= r. + + @retval EFI_SUCCESS The dispatch function has been successfu= lly + unregistered and the SMI source has been= disabled + if there are no other registered child d= ispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + BOOLEAN NeedClearEnable; + UINTN DescIndex; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + if (DispatchHandle =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + + // + // Take the entry out of the linked list + // + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) EFI_BAD_POINT= ER) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + + // + // Loop through all the souces in record linked list to see if any sourc= e enable is equal. + // If any source enable is equal, we do not want to disable it. + // + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) { + continue; + } + NeedClearEnable =3D TRUE; + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); + if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex],= &RecordInDb->SrcDesc)) { + NeedClearEnable =3D FALSE; + break; + } + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInD= b->Link); + } + if (NeedClearEnable =3D=3D FALSE) { + continue; + } + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE); + } + Status =3D gSmst->SmmFreePool (RecordToDelete); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + return EFI_SUCCESS; +} + +/** + This function clears the pending SMI status before set EOS. + NOTE: This only clears the pending SMI with known reason. + Please do not clear unknown pending SMI status since that will hid= e potential issues. + + @param[in] SmiStsValue SMI status + @param[in] SciEn Sci Enable status +**/ +STATIC +VOID +ClearPendingSmiStatus ( + UINT32 SmiStsValue, + BOOLEAN SciEn + ) +{ + // + // Clear NewCentury status if it's not handled. + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) { + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & B_TCO_IO_TCO1_STS_NE= WCENTURY) { + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury); + } + } + // Clear PWRBTNOR_STS if it's not handled. + // + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & B_ACPI_IO_PM1_STS_PRB= TNOR) { + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PRBTNO= R); + } + // + // Clear WADT_STS if this is triggered by WADT timer. + // + if (!SciEn) { + if ((IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96) & B_ACPI_IO_G= PE0_EN_127_96_WADT) && + (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & B_ACPI_IO_= GPE0_STS_127_96_WADT)) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0= _STS_127_96_WADT); + } + } + // + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not= supported + // + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) { + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, B_ACPI_IO_SMI_STS_GPIO_U= NLOCK); + } +} + +/** + The callback function to handle subsequent SMIs. This callback will be = called by SmmCoreDispatcher. + + @param[in] SmmImageHandle Not used + @param[in] PchSmmCore Not used + @param[in, out] CommunicationBuffer Not used + @param[in, out] SourceSize Not used + + @retval EFI_SUCCESS Function successfully completed +**/ +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN CONST VOID *PchSmmCore, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + // + // Used to prevent infinite loops + // + UINTN EscapeCount; + + BOOLEAN ContextsMatch; + BOOLEAN EosSet; + BOOLEAN SxChildWasDispatched; + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + DATABASE_RECORD *RecordToExhaust; + LIST_ENTRY *LinkToExhaust; + + PCH_SMM_CONTEXT Context; + VOID *CommBuffer; + UINTN CommBufferSize; + + EFI_STATUS Status; + BOOLEAN SciEn; + UINT32 SmiEnValue; + UINT32 SmiStsValue; + UINT8 Port74Save; + UINT8 Port76Save; + + PCH_SMM_SOURCE_DESC ActiveSource; + + // + // Initialize ActiveSource + // + NullInitSourceDesc (&ActiveSource); + + EscapeCount =3D 3; + ContextsMatch =3D FALSE; + EosSet =3D FALSE; + SxChildWasDispatched =3D FALSE; + Status =3D EFI_SUCCESS; + + // + // Save IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8 + // + Port76Save =3D IoRead8 (R_RTC_IO_EXT_INDEX_ALT); + Port74Save =3D IoRead8 (R_RTC_IO_INDEX_ALT); + + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { + // + // We have children registered w/ us -- continue + // + while ((!EosSet) && (EscapeCount > 0)) { + EscapeCount--; + + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); + + // + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is= active + // + SciEn =3D PchSmmGetSciEn (); + SmiEnValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)= ); + SmiStsValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS= )); + + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); + + // + // look for the first active source + // + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, SmiS= tsValue)) { + // + // Didn't find the source yet, keep looking + // + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &Recor= dInDb->Link); + + // + // if it's the last one, try to clear EOS + // + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + EosSet =3D PchSmmSetAndCheckEos (); + } + } else { + // + // We found a source. If this is a sleep type, we have to go to + // appropriate sleep state anyway.No matter there is sleep child= or not + // + if (RecordInDb->ProtocolType =3D=3D SxType) { + SxChildWasDispatched =3D TRUE; + } + // + // "cache" the source description and don't query I/O anymore + // + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc)= , sizeof (PCH_SMM_SOURCE_DESC)); + LinkToExhaust =3D LinkInDb; + + // + // exhaust the rest of the queue looking for the same source + // + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) = { + RecordToExhaust =3D DATABASE_RECORD_FROM_LINK (LinkToExhaust); + // + // RecordToExhaust->Link might be removed (unregistered) by Ca= llback function, and then the + // system will hang in ASSERT() while calling GetNextNode(). + // To prevent the issue, we need to get next record in DB here= (before Callback function). + // + LinkToExhaust =3D GetNextNode (&mPrivateData.CallbackDataBase,= &RecordToExhaust->Link); + + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource))= { + // + // These source descriptions are equal, so this callback sho= uld be + // dispatched. + // + if (RecordToExhaust->ContextFunctions.GetContext !=3D NULL) = { + // + // This child requires that we get a calling context from + // hardware and compare that context to the one supplied + // by the child. + // + ASSERT (RecordToExhaust->ContextFunctions.CmpContext !=3D = NULL); + + // + // Make sure contexts match before dispatching event to ch= ild + // + RecordToExhaust->ContextFunctions.GetContext (RecordToExha= ust, &Context); + ContextsMatch =3D RecordToExhaust->ContextFunctions.CmpCon= text (&Context, &RecordToExhaust->ChildContext); + + } else { + // + // This child doesn't require any more calling context bey= ond what + // it supplied in registration. Simply pass back what it = gave us. + // + Context =3D RecordToExhaust->ChildContext; + ContextsMatch =3D TRUE; + } + + if (ContextsMatch) { + if (RecordToExhaust->ProtocolType =3D=3D PchSmiDispatchTyp= e) { + // + // For PCH SMI dispatch protocols + // + PchSmiTypeCallbackDispatcher (RecordToExhaust); + } else { + if ((RecordToExhaust->ProtocolType =3D=3D SxType) && (Co= ntext.Sx.Type =3D=3D SxS3) && (Context.Sx.Phase =3D=3D SxEntry) && !mS3SusS= tart) { + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S= 3_SUSPEND_START); + mS3SusStart =3D TRUE; + } + // + // For EFI standard SMI dispatch protocols + // + if (RecordToExhaust->Callback !=3D NULL) { + if (RecordToExhaust->ContextFunctions.GetCommBuffer != =3D NULL) { + // + // This callback function needs CommBuffer and CommB= ufferSize. + // Get those from child and then pass to callback fu= nction. + // + RecordToExhaust->ContextFunctions.GetCommBuffer (Rec= ordToExhaust, &CommBuffer, &CommBufferSize); + } else { + // + // Child doesn't support the CommBuffer and CommBuff= erSize. + // Just pass NULL value to callback function. + // + CommBuffer =3D NULL; + CommBufferSize =3D 0; + } + + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (= ), RecordToExhaust->ProtocolType); + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExha= ust->Link, &Context, CommBuffer, &CommBufferSize); + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (),= RecordToExhaust->ProtocolType); + if (RecordToExhaust->ProtocolType =3D=3D SxType) { + SxChildWasDispatched =3D TRUE; + } + } else { + ASSERT (FALSE); + } + } + } + } + } + + if (RecordInDb->ClearSource =3D=3D NULL) { + // + // Clear the SMI associated w/ the source using the default fu= nction + // + PchSmmClearSource (&ActiveSource); + } else { + // + // This source requires special handling to clear + // + RecordInDb->ClearSource (&ActiveSource); + } + // + // Clear pending SMI status before EOS + // + ClearPendingSmiStatus (SmiStsValue, SciEn); + // + // Also, try to clear EOS + // + EosSet =3D PchSmmSetAndCheckEos (); + // + // Queue is empty, reset the search + // + break; + } + } + } + } + // + // Restore IO index registers + // @note: Save/Restore port 70h directly might break NMI_EN# setting, + // then save/restore 74h/76h instead. + // + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save); + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save); + + return Status; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmGpi.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSm= mGpi.c new file mode 100644 index 0000000000..4c59c07bac --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.= c @@ -0,0 +1,255 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Gpi dispatch= protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +#include +#include +#include + +// +// Structure for GPI SMI is a template which needs to have +// GPI Smi bit offset and Smi Status & Enable registers updated (according= ly +// to choosen group and pad number) after adding it to SMM Callback databa= se +// + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPchGpiSourceDescT= emplate =3D { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + GPIO_ADDR_TYPE, {0x0} + }, + S_GPIO_PCR_GP_SMI_STS, 0x0, + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_GPIO_SMI + } +}; + +/** + The register function used to register SMI handler of GPI SMI event. + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PROT= OCOL instance. + @param[in] DispatchFunction Function to register for handler when the= specified GPI causes an SMI. + @param[in] RegisterContext Pointer to the dispatch function's contex= t. + The caller fills this context in before c= alling + the register function to indicate to the = register + function the GPI(s) for which the dispatc= h function + should be invoked. + @param[out] DispatchHandle Handle generated by the dispatcher to tra= ck the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successful= ly + registered and the SMI source has been en= abled. + @retval EFI_ACCESS_DENIED Register is not allowed + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI input= value + is not within valid range. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this child. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD Record; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32And; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event ha= s been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + Status =3D GpioGetPadAndSmiRegs ( + (UINT32) RegisterContext->GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + + // + // Gather information about the registration request + // + Record.Callback =3D DispatchFunction; + Record.ChildContext.Gpi =3D *RegisterContext; + Record.ProtocolType =3D GpiType; + Record.Signature =3D DATABASE_RECORD_SIGNATURE; + + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof (PCH_SMM_SO= URCE_DESC) ); + + Record.SrcDesc.Sts[0].Reg.Data.raw =3D GpiSmiStsRegAddress; // GPI SMI = Status register + Record.SrcDesc.Sts[0].Bit =3D GpiSmiBitOffset; // Bit posi= tion for selected pad + + // + // Insert GpiSmi handler to PchSmmCore database + // + *DispatchHandle =3D NULL; + + Status =3D SmmCoreInsertRecord ( + &Record, + DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + SmiHandlerProfileRegisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, + (UINTN)RETURN_ADDRESS (0), + RegisterContext, + sizeof(*RegisterContext) + ); + + // + // Enable GPI SMI + // HOSTSW_OWN with respect to generating GPI SMI has negative logic: + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI + // + Data32And =3D (UINT32)~(1u << GpiSmiBitOffset); + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And); + + return EFI_SUCCESS; +} + +/** + Unregister a GPI SMI source dispatch function with a parent SMM driver + + @param[in] This Pointer to the EFI_SMM_GPI_DISPATCH2_PRO= TOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregiste= r. + + @retval EFI_SUCCESS The dispatch function has been successfu= lly + unregistered and the SMI source has been= disabled + if there are no other registered child d= ispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +EFIAPI +PchGpiSmiUnRegister ( + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + GPIO_PAD GpioPad; + UINT8 GpiSmiBitOffset; + UINT32 GpiHostSwOwnRegAddress; + UINT32 GpiSmiStsRegAddress; + UINT32 Data32Or; + UINT32 Data32And; + BOOLEAN DisableGpiSmiSource; + + + if (DispatchHandle =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + if ((RecordToDelete->Signature !=3D DATABASE_RECORD_SIGNATURE) || + (RecordToDelete->ProtocolType !=3D GpiType)) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + DisableGpiSmiSource =3D TRUE; + // + // Loop through all sources in record linked list to see if any other GP= I SMI + // is installed on the same pin. If no then disable GPI SMI capability o= n this pad + // + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb-= >Link); + // + // If this is the record to delete skip it + // + if (RecordInDb =3D=3D RecordToDelete) { + continue; + } + // + // Check if record is GPI SMI type + // + if (RecordInDb->ProtocolType =3D=3D GpiType) { + // + // Check if same GPIO pad is the source of this SMI + // + if (RecordInDb->ChildContext.Gpi.GpiNum =3D=3D RecordToDelete->Child= Context.Gpi.GpiNum) { + DisableGpiSmiSource =3D FALSE; + break; + } + } + } + + if (DisableGpiSmiSource) { + GpioGetPadAndSmiRegs ( + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum, + &GpioPad, + &GpiSmiBitOffset, + &GpiHostSwOwnRegAddress, + &GpiSmiStsRegAddress + ); + + Data32Or =3D 1u << GpiSmiBitOffset; + Data32And =3D 0xFFFFFFFF; + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or); + } + + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD)); + Status =3D gSmst->SmmFreePool (RecordToDelete); + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + SmiHandlerProfileUnregisterHandler ( + &gEfiSmmGpiDispatch2ProtocolGuid, + RecordToDelete->Callback, + &RecordToDelete->ChildContext, + RecordToDelete->ContextSize + ); + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/P= chSmmHelpers.c new file mode 100644 index 0000000000..724a383855 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp= ers.c @@ -0,0 +1,332 @@ +/** @file + Helper functions for PCH SMM dispatcher. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include + +/// +/// #define BIT_ZERO 0x00000001 +/// +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =3D 0x00000001; + +/// +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +/// + +/** + Compare 2 SMM source descriptors' enable settings. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The enable settings of the 2 SMM source = descriptors are identical. + @retval FALSE The enable settings of the 2 SMM source = descriptors are not identical. +**/ +BOOLEAN +CompareEnables ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + BOOLEAN IsEqual; + UINTN DescIndex; + + IsEqual =3D TRUE; + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { + /// + /// It's okay to compare a NULL bit description to a non-NULL bit desc= ription. + /// They are unequal and these tests will generate the correct result. + /// + if (Src1->En[DescIndex].Bit !=3D Src2->En[DescIndex].Bit || + Src1->En[DescIndex].Reg.Type !=3D Src2->En[DescIndex].Reg.Type || + Src1->En[DescIndex].Reg.Data.raw !=3D Src2->En[DescIndex].Reg.Data= .raw + ) { + IsEqual =3D FALSE; + break; + /// + /// out of for loop + /// + } + } + + return IsEqual; +} + +/** + Compare a bit descriptor to the enables of source descriptor. Includes n= ull address type. + + @param[in] BitDesc Pointer to the PCH SMI bit descriptor + @param[in] Src Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The bit desc is equal to any of the enab= les in source descriptor + @retval FALSE The bid desc is not equal to all of the = enables in source descriptor +**/ +BOOLEAN +IsBitEqualToAnySourceEn ( + CONST IN PCH_SMM_BIT_DESC *BitDesc, + CONST IN PCH_SMM_SOURCE_DESC *Src + ) +{ + BOOLEAN IsEqual; + UINTN DescIndex; + + IsEqual =3D FALSE; + + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { + if ((BitDesc->Reg.Type =3D=3D Src->En[DescIndex].Reg.Type) && + (BitDesc->Reg.Data.raw =3D=3D Src->En[DescIndex].Reg.Data.raw) && + (BitDesc->Bit =3D=3D Src->En[DescIndex].Bit)) { + IsEqual =3D TRUE; + break; + } + } + return IsEqual; +} + +/** + Compare 2 SMM source descriptors' statuses. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The statuses of the 2 SMM source descrip= tors are identical. + @retval FALSE The statuses of the 2 SMM source descrip= tors are not identical. +**/ +BOOLEAN +CompareStatuses ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + BOOLEAN IsEqual; + UINTN DescIndex; + + IsEqual =3D TRUE; + + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { + /// + /// It's okay to compare a NULL bit description to a non-NULL bit desc= ription. + /// They are unequal and these tests will generate the correct result. + /// + if (Src1->Sts[DescIndex].Bit !=3D Src2->Sts[DescIndex].Bit || + Src1->Sts[DescIndex].Reg.Type !=3D Src2->Sts[DescIndex].Reg.Type |= | + Src1->Sts[DescIndex].Reg.Data.raw !=3D Src2->Sts[DescIndex].Reg.Da= ta.raw + ) { + IsEqual =3D FALSE; + break; + /// + /// out of for loop + /// + } + } + + return IsEqual; +} + +/** + Compare 2 SMM source descriptors, based on Enable settings and Status se= ttings of them. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The 2 SMM source descriptors are identic= al. + @retval FALSE The 2 SMM source descriptors are not ide= ntical. +**/ +BOOLEAN +CompareSources ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, = Src2)); +} + +/** + Check if an SMM source is active. + + @param[in] Src Pointer to the PCH SMI source descriptio= n table + @param[in] SciEn Indicate if SCI is enabled or not + @param[in] SmiEnValue Value from R_ACPI_IO_SMI_EN + @param[in] SmiStsValue Value from R_ACPI_IO_SMI_STS + + @retval TRUE It is active. + @retval FALSE It is inactive. +**/ +BOOLEAN +SourceIsActive ( + CONST IN PCH_SMM_SOURCE_DESC *Src, + CONST IN BOOLEAN SciEn, + CONST IN UINT32 SmiEnValue, + CONST IN UINT32 SmiStsValue + ) +{ + UINTN DescIndex; + + /// + /// This source is dependent on SciEn, and SciEn =3D=3D 1. An ACPI OS i= s present, + /// so we shouldn't do anything w/ this source until SciEn =3D=3D 0. + /// + if ((Src->Flags =3D=3D PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) { + return FALSE; + } + + /// + /// Checking top level SMI status. If the status is not active, return f= alse immediately + /// + if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) { + if ((Src->PmcSmiSts.Reg.Type =3D=3D ACPI_ADDR_TYPE) && + (Src->PmcSmiSts.Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) && + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) =3D=3D 0)) { + return FALSE; + } + } + + /// + /// Read each bit desc from hardware and make sure it's a one + /// + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) { + if ((Src->En[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && + (Src->En[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_EN) && + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) =3D=3D 0)) { + return FALSE; + } else if (ReadBitDesc (&Src->En[DescIndex]) =3D=3D 0) { + return FALSE; + } + } + } + + /// + /// Read each bit desc from hardware and make sure it's a one + /// + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) { + if ((Src->Sts[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && + (Src->Sts[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) && + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) =3D=3D 0)) { + return FALSE; + } else if (ReadBitDesc (&Src->Sts[DescIndex]) =3D=3D 0) { + return FALSE; + } + } + } + + return TRUE; +} + +/** + Enable the SMI source event by set the SMI enable bit, this function wou= ld also clear SMI + status bit to make initial state is correct + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmEnableSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN DescIndex; + + /// + /// Set enables to 1 by writing a 1 + /// + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { + WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE); + } + } + /// + /// Clear statuses to 0 by writing a 1 + /// + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); + } + } +} + +/** + Disable the SMI source event by clear the SMI enable bit + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmDisableSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN DescIndex; + + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { + WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE); + } + } +} + +/** + Clear the SMI status bit by set the source bit of SMI status register + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN DescIndex; + + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); + } + } +} + +/** + Sets the source to a 1 and then waits for it to clear. + Be very careful when calling this function -- it will not + ASSERT. An acceptable case to call the function is when + waiting for the NEWCENTURY_STS bit to clear (which takes + 3 RTCCLKs). + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN DescIndex; + BOOLEAN IsSet; + + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { + + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { + /// + /// Write the bit + /// + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); + + /// + /// Don't return until the bit actually clears. + /// + IsSet =3D TRUE; + while (IsSet) { + IsSet =3D ReadBitDesc (&SrcDesc->Sts[DescIndex]); + /// + /// IsSet will eventually clear -- or else we'll have + /// an infinite loop. + /// + } + } + } +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/P= chSmmHelpers.h new file mode 100644 index 0000000000..93ab8564ff --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelp= ers.h @@ -0,0 +1,163 @@ +/** @file + Helper functions for PCH SMM + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef PCH_SMM_HELPERS_H +#define PCH_SMM_HELPERS_H + +#include "PchSmm.h" +#include "PchxSmmHelpers.h" +// +// ///////////////////////////////////////////////////////////////////////= //////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +// + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ); + +/** + Compare 2 SMM source descriptors' enable settings. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The enable settings of the 2 SMM source = descriptors are identical. + @retval FALSE The enable settings of the 2 SMM source = descriptors are not identical. +**/ +BOOLEAN +CompareEnables ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Compare a bit descriptor to the enables of source descriptor. Includes n= ull address type. + + @param[in] BitDesc Pointer to the PCH SMI bit descriptor + @param[in] Src Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The bit desc is equal to any of the enab= les in source descriptor + @retval FALSE The bid desc is not equal to all of the = enables in source descriptor +**/ +BOOLEAN +IsBitEqualToAnySourceEn ( + CONST IN PCH_SMM_BIT_DESC *BitDesc, + CONST IN PCH_SMM_SOURCE_DESC *Src + ); + +/** + Compare 2 SMM source descriptors' statuses. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The statuses of the 2 SMM source descrip= tors are identical. + @retval FALSE The statuses of the 2 SMM source descrip= tors are not identical. +**/ +BOOLEAN +CompareStatuses ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Compare 2 SMM source descriptors, based on Enable settings and Status se= ttings of them. + + @param[in] Src1 Pointer to the PCH SMI source descriptio= n table 1 + @param[in] Src2 Pointer to the PCH SMI source descriptio= n table 2 + + @retval TRUE The 2 SMM source descriptors are identic= al. + @retval FALSE The 2 SMM source descriptors are not ide= ntical. +**/ +BOOLEAN +CompareSources ( + CONST IN PCH_SMM_SOURCE_DESC *Src1, + CONST IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Check if an SMM source is active. + + @param[in] Src Pointer to the PCH SMI source descriptio= n table + @param[in] SciEn Indicate if SCI is enabled or not + @param[in] SmiEnValue Value from R_PCH_SMI_EN + @param[in] SmiStsValue Value from R_PCH_SMI_STS + + @retval TRUE It is active. + @retval FALSE It is inactive. +**/ +BOOLEAN +SourceIsActive ( + CONST IN PCH_SMM_SOURCE_DESC *Src, + CONST IN BOOLEAN SciEn, + CONST IN UINT32 SmiEnValue, + CONST IN UINT32 SmiStsValue + ); + +/** + Enable the SMI source event by set the SMI enable bit, this function wou= ld also clear SMI + status bit to make initial state is correct + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmEnableSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Disable the SMI source event by clear the SMI enable bit + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmDisableSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Clear the SMI status bit by set the source bit of SMI status register + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmClearSource ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Sets the source to a 1 and then waits for it to clear. + Be very careful when calling this function -- it will not + ASSERT. An acceptable case to call the function is when + waiting for the NEWCENTURY_STS bit to clear (which takes + 3 RTCCLKs). + + @param[in] SrcDesc Pointer to the PCH SMI source descriptio= n table + +**/ +VOID +PchSmmClearSourceAndBlock ( + CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Performs update of SmmUsb descriptors with values that have to be evalua= ted during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmPeriodicTimer.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher= /Smm/PchSmmPeriodicTimer.c new file mode 100644 index 0000000000..3078d0c696 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri= odicTimer.c @@ -0,0 +1,670 @@ +/** @file + File to contain all the hardware specific stuff for the Periodical Timer= dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include + +// +// There is only one instance for PeriodicTimerCommBuffer. +// It's safe in SMM since there is no re-entry for the function. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT mPch= PeriodicTimerCommBuffer; + +typedef enum { + PERIODIC_TIMER=3D 0, + SWSMI_TIMER, + NUM_TIMERS +} SUPPORTED_TIMER; + +typedef struct _TIMER_INTERVAL { + UINT64 Interval; + UINT8 AssociatedTimer; +} TIMER_INTERVAL; + +#define NUM_INTERVALS 8 + +// +// Time constants, in 100 nano-second units +// +#define TIME_64s 640000000 ///< 64 s +#define TIME_32s 320000000 ///< 32 s +#define TIME_16s 160000000 ///< 16 s +#define TIME_8s 80000000 ///< 8 s +#define TIME_64ms 640000 ///< 64 ms +#define TIME_32ms 320000 ///< 32 ms +#define TIME_16ms 160000 ///< 16 ms +#define TIME_1_5ms 15000 ///< 1.5 ms + +typedef enum { + INDEX_TIME_64s =3D 0, + INDEX_TIME_32s, + INDEX_TIME_16s, + INDEX_TIME_8s, + INDEX_TIME_64ms, + INDEX_TIME_32ms, + INDEX_TIME_16ms, + INDEX_TIME_1_5ms, + INDEX_TIME_MAX +} TIMER_INTERVAL_INDEX; + +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] =3D { + { + TIME_64s, + PERIODIC_TIMER + }, + { + TIME_32s, + PERIODIC_TIMER + }, + { + TIME_16s, + PERIODIC_TIMER + }, + { + TIME_8s, + PERIODIC_TIMER + }, + { + TIME_64ms, + SWSMI_TIMER + }, + { + TIME_32ms, + SWSMI_TIMER + }, + { + TIME_16ms, + SWSMI_TIMER + }, + { + TIME_1_5ms, + SWSMI_TIMER + }, +}; + +typedef struct _TIMER_INFO { + UINTN NumChildren; ///< number of children using this timer + UINT64 MinReqInterval; ///< minimum interval required by children + UINTN CurrentSetting; ///< interval this timer is set at right now= (index into interval table) +} TIMER_INFO; + +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO mTimers[NUM_TIMERS]; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mTimerSourceDesc[N= UM_TIMERS] =3D { + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_PERIODIC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PERIODIC + } + }, + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_SWSMI_TMR + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_SWSMI_TMR + } + } +}; + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Convert the dispatch context to the timer interval, this function will a= ssert if then either: + (1) The context contains an invalid interval + (2) The timer interval table is corrupt + + @param[in] DispatchContext The pointer to the Dispatch Context + + @retval TIMER_INTERVAL The timer interval of input dispatch con= text +**/ +TIMER_INTERVAL * +ContextToTimerInterval ( + IN PCH_SMM_CONTEXT *DispatchContext + ) +{ + UINTN loopvar; + + /// + /// Determine which timer this child is using + /// + for (loopvar =3D 0; loopvar < NUM_INTERVALS; loopvar++) { + if (((DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D 0) && + (DispatchContext->PeriodicTimer.Period >=3D mSmmPeriodicTimerInte= rvals[loopvar].Interval)) || + (DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D mSmmPeriodi= cTimerIntervals[loopvar].Interval)) { + return &mSmmPeriodicTimerIntervals[loopvar]; + } + } + /// + /// If this assertion fires, then either: + /// (1) the context contains an invalid interval + /// (2) the timer interval table is corrupt + /// + ASSERT (FALSE); + + return NULL; +} + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context inst= ances + @param[out] SrcDesc The pointer to the source description + +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + TIMER_INTERVAL *TimerInterval; + + /// + /// Figure out which timer the child is requesting and + /// send back the source description + /// + TimerInterval =3D ContextToTimerInterval (DispatchContext); + if (TimerInterval =3D=3D NULL) { + return; + } + + CopyMem ( + (VOID *) SrcDesc, + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + + /// + /// Program the value of the interval into hardware + /// + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. + +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *HwContext + ) +{ + TIMER_INTERVAL *TimerInterval; + + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); + + TimerInterval =3D ContextToTimerInterval (&Record->ChildContext); + if (TimerInterval =3D=3D NULL) { + return; + } + /// + /// Ignore the hardware context. It's not required for this protocol. + /// Instead, just increment the child's context. + /// Update the elapsed time w/ the data from our tables + /// + Record->MiscData.ElapsedTime +=3D mTimers[TimerInterval->AssociatedTimer= ].MinReqInterval; + *HwContext =3D Record->ChildContext; +} + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer = 1 + @param[in] Context2 Context 2 that includes Periodic Timer = 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *HwContext, + IN PCH_SMM_CONTEXT *ChildContext + ) +{ + DATABASE_RECORD *Record; + Record =3D DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext); + + if (!Record->MiscData.TimerSmiEnabled) { + return FALSE; + } + if (Record->MiscData.ElapsedTime >=3D ChildContext->PeriodicTimer.Period= ) { + /// + /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffe= r + /// + return TRUE; + } else { + return FALSE; + } +} + +/** + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. + + @param[in] Record No use + @param[out] CommBuffer Point to the CommBuffer structure + @param[out] CommBufferSize Point to the Size of CommBuffer structur= e + +**/ +VOID +EFIAPI +PeriodicTimerGetCommBuffer ( + IN DATABASE_RECORD *Record, + OUT VOID **CommBuffer, + OUT UINTN *CommBufferSize + ) +{ + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); + + mPchPeriodicTimerCommBuffer.ElapsedTime =3D Record->MiscData.ElapsedTime= ; + + /// + /// For EDKII, the ElapsedTime is reset here + /// + Record->MiscData.ElapsedTime =3D 0; + + /// + /// Return the CommBuffer + /// + *CommBuffer =3D (VOID *) &mPchPeriodicTimerCommBuffer; + *CommBufferSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); +} + +/** + Program Smm Periodic Timer + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce. +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + SUPPORTED_TIMER Timer; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + TIMER_INTERVAL *TimerInterval; + + /// + /// Find the minimum required interval for each timer + /// + for (Timer =3D 0; Timer < NUM_TIMERS; Timer++) { + mTimers[Timer].MinReqInterval =3D ~ (UINT64) 0x0; + mTimers[Timer].NumChildren =3D 0; + } + + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { + if (RecordInDb->MiscData.TimerSmiEnabled) { + /// + /// This child is registerd with the PeriodicTimer protocol + /// + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildContex= t); + if (TimerInterval =3D=3D NULL) { + return; + } + + Timer =3D TimerInterval->AssociatedTimer; + if (Timer < 0 || Timer >=3D NUM_TIMERS) { + ASSERT (FALSE); + CpuDeadLoop (); + return; + } + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.Perio= dicTimer.SmiTickInterval) { + mTimers[Timer].MinReqInterval =3D RecordInDb->ChildContext.Perio= dicTimer.SmiTickInterval; + } + mTimers[Timer].NumChildren++; + } + } + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb-= >Link); + } + /// + /// Program the hardware + /// + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { + case TIME_64s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s); + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_64s; + break; + + case TIME_32s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s); + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_32s; + break; + + case TIME_16s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s); + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_16s; + break; + + case TIME_8s: + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s); + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_8s; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, just need to clear the SMI + /// + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_PERIODIC) { + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]); + } + + if (mTimers[SWSMI_TIMER].NumChildren > 0) { + switch (mTimers[SWSMI_TIMER].MinReqInterval) { + case TIME_64ms: + PmcSetSwSmiRate (PmcSwSmiRate64ms); + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_64ms; + break; + + case TIME_32ms: + PmcSetSwSmiRate (PmcSwSmiRate32ms); + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_32ms; + break; + + case TIME_16ms: + PmcSetSwSmiRate (PmcSwSmiRate16ms); + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_16ms; + break; + + case TIME_1_5ms: + PmcSetSwSmiRate (PmcSwSmiRate1p5ms); + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_1_5ms; + break; + + default: + ASSERT (FALSE); + break; + } + + /// + /// Restart the timer here, need to disable, clear, then enable to res= tart this timer + /// + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_SWSMI_TMR) { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]); + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } + } else { + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); + } +} + +/** + This services returns the next SMI tick period that is supported by the = chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DI= SPATCH2_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter S= MI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid= . +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +{ + TIMER_INTERVAL *IntervalPointer; + + ASSERT (SmiTickInterval !=3D NULL); + if (SmiTickInterval =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + IntervalPointer =3D (TIMER_INTERVAL *) *SmiTickInterval; + + if (IntervalPointer =3D=3D NULL) { + /// + /// The first time child requesting an interval + /// + IntervalPointer =3D &mSmmPeriodicTimerIntervals[0]; + } else if (IntervalPointer =3D=3D &mSmmPeriodicTimerIntervals[NUM_INTERV= ALS - 1]) { + /// + /// At end of the list + /// + IntervalPointer =3D NULL; + } else { + if ((IntervalPointer >=3D &mSmmPeriodicTimerIntervals[0]) && + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) + ) { + /// + /// Get the next interval in the list + /// + IntervalPointer++; + } else { + /// + /// Input is out of range + /// + return EFI_INVALID_PARAMETER; + } + } + + if (IntervalPointer !=3D NULL) { + *SmiTickInterval =3D &IntervalPointer->Interval; + } else { + *SmiTickInterval =3D NULL; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for calculating and enabling any timers tha= t are required + to dispatch messages to children. The SrcDesc argument isn't acutally us= ed. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC insta= nce. + +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmPeriodicTimerProgramTimers (SrcDesc); +} + + +/** + Check if the handle is in type of PeriodicTimer + + @retval TRUE The handle is in type of PeriodicT= imer. + @retval FALSE The handle is not in type of Perio= dicTimer. +**/ +BOOLEAN +IsSmmPeriodicTimerHandle ( + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + if (DispatchHandle =3D=3D (EFI_HANDLE) LinkInDb) { + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { + return TRUE; + } + } + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); + } + return FALSE; +} + +/** + Pause SMM periodic timer callback function. + + This function disable the SMI enable of SMI timer according to the Dispa= tchHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlPause ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { + return EFI_INVALID_PARAMETER; + } + + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled =3D FALSE; + // + // reset the timer interval per SMI trigger due to stop a periodic timer= SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +/** + Resume SMM periodic timer callback function. + + This function enable the SMI enable of SMI timer according to the Dispat= chHandle, + which is returned by SMM periodic timer callback registration. + + @retval EFI_SUCCESS This operation is complete. + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. +**/ +EFI_STATUS +EFIAPI +PchSmmPeriodicTimerControlResume ( + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + DATABASE_RECORD *RecordInDb; + + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { + return EFI_INVALID_PARAMETER; + } + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); + RecordInDb->MiscData.TimerSmiEnabled =3D TRUE; + // + // reset the timer interval per SMI trigger due to resume a periodic tim= er SMI + // + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); + return EFI_SUCCESS; +} + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL mPch= SmmPeriodicTimerControlProtocol =3D { + PchSmmPeriodicTimerControlPause, + PchSmmPeriodicTimerControlResume +}; + +/** + Install PCH SMM periodic timer control protocol + + @param[in] Handle handle for this driver + + @retval EFI_SUCCESS Driver initialization completed su= ccessfully +**/ +EFI_STATUS +EFIAPI +InstallPchSmmPeriodicTimerControlProtocol ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + + // + // Install protocol interface + // + Status =3D gSmst->SmmInstallProtocolInterface ( + &Handle, + &gPchSmmPeriodicTimerControlGuid, + EFI_NATIVE_INTERFACE, + &mPchSmmPeriodicTimerControlProtocol + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmPowerButton.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/S= mm/PchSmmPowerButton.c new file mode 100644 index 0000000000..e6d3bf012f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowe= rButton.c @@ -0,0 +1,77 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Power Button= dispatch protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPowerButtonSource= Desc =3D { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_EN} + }, + S_ACPI_IO_PM1_EN, + N_ACPI_IO_PM1_EN_PWRBTN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_PM1_STS} + }, + S_ACPI_IO_PM1_STS, + N_ACPI_IO_PM1_STS_PWRBTN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_PM1_STS_REG + } +}; + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will = be updated with the current power button status. + +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + return; +} + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button sta= tus 1 + @param[in] Context2 Context 2 that includes Power Button sta= tus 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return TRUE; +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmSw.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm= Sw.c new file mode 100644 index 0000000000..311a21820c --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c @@ -0,0 +1,381 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sw dispatch = protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpuProtoc= ol; + +STATIC LIST_ENTRY mSwSmiCallbackDataBase; + +// +// "SWSMI" RECORD +// Linked list data structures +// +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M') + +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, SW_SMI_RECORD, Link= , SW_SMI_RECORD_SIGNATURE) + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_SMM_SW_REGISTER_CONTEXT Context; + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; +} SW_SMI_RECORD; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSwSourceDesc =3D = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_APMC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_APM + } +}; + +/** + Check the SwSmiInputValue to see if there is a duplicated one in the dat= abase + + @param[in] SwSmiInputValue SwSmiInputValue + + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue +**/ +EFI_STATUS +SmiInputValueDuplicateCheck ( + IN UINTN SwSmiInputValue + ) +{ + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link)= ; + } + + return EFI_SUCCESS; +} + +/** + Register a child SMI source dispatch function for the specified software= SMI. + + This service registers a function (DispatchFunction) which will be calle= d when the software + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On r= eturn, + DispatchHandle contains a unique handle which may be used later to unreg= ister the function + using UnRegister(). + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PRO= TOCOL instance. + @param[in] DispatchFunction Function to register for handler when t= he specified software + SMI is generated. + @param[in, out] RegisterContext Pointer to the dispatch function's cont= ext. + The caller fills this context in before= calling + the register function to indicate to th= e register + function which Software SMI input value= the + dispatch function should be invoked for= . + @param[out] DispatchHandle Handle generated by the dispatcher to t= rack the + function instance. + + @retval EFI_SUCCESS The dispatch function has been successful= ly + registered and the SMI source has been en= abled. + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SM= I source. + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI in= put value + is not within a valid range or is already= in use. + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM= ) to manage this + child. + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be = assigned + for this dispatch. +**/ +EFI_STATUS +EFIAPI +PchSwSmiRegister ( + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *SwSmiRecord; + UINTN Index; + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock ev= ent has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + // + // Find available SW SMI value if the input is -1 + // + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { + for (Index =3D 1; Index < MAXIMUM_SWI_VALUE; Index++) { + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) { + DispatchContext->SwSmiInputValue =3D Index; + break; + } + } + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { + return EFI_OUT_OF_RESOURCES; + } + } + // + // Check if it's a valid SW SMI value. + // The value must not bigger than 0xFF. + // And the value must not be 0xFF sincie it's used for SmmControll proto= col. + // + if (DispatchContext->SwSmiInputValue >=3D MAXIMUM_SWI_VALUE) { + return EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext->SwSmiInputV= alue))) { + return EFI_INVALID_PARAMETER; + } + + // + // Create database record and add to database + // + Status =3D gSmst->SmmAllocatePool ( + EfiRuntimeServicesData, + sizeof (SW_SMI_RECORD), + (VOID **) &SwSmiRecord + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! \n"))= ; + return EFI_OUT_OF_RESOURCES; + } + // + // Gather information about the registration request + // + SwSmiRecord->Signature =3D SW_SMI_RECORD_SIGNATURE; + SwSmiRecord->Context.SwSmiInputValue =3D DispatchContext->SwSmiInputValu= e; + SwSmiRecord->Callback =3D DispatchFunction; + // + // Publish the S/W SMI numbers in Serial logs used for Debug build. + // + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", SwSmiR= ecord->Context.SwSmiInputValue, SwSmiRecord)); + + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle =3D (EFI_HANDLE) (&SwSmiRecord->Link); + + return EFI_SUCCESS; +} + +/** + Unregister a child SMI source dispatch function for the specified softwa= re SMI. + + This service removes the handler associated with DispatchHandle so that = it will no longer be + called in response to a software SMI. + + @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTO= COL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister= . + + @retval EFI_SUCCESS The dispatch function has been successful= ly unregistered. + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. +**/ +EFI_STATUS +EFIAPI +PchSwSmiUnRegister ( + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +{ + EFI_STATUS Status; + SW_SMI_RECORD *RecordToDelete; + + if (DispatchHandle =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Return access denied if the SmmReadyToLock event has been triggered + // + if (mReadyToLock =3D=3D TRUE) { + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock = event has been triggered! \n")); + return EFI_ACCESS_DENIED; + } + + RecordToDelete =3D SW_SMI_RECORD_FROM_LINK (DispatchHandle); + // + // Take the entry out of the linked list + // + if (RecordToDelete->Signature !=3D SW_SMI_RECORD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD)); + Status =3D gSmst->SmmFreePool (RecordToDelete); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Main entry point for an SMM handler dispatch or communicate-based callba= ck. + + @param[in] DispatchHandle The unique handle assigned to this handle= r by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context whi= ch was specified when the + handler was registered. + @param[in,out] CommBuffer A pointer to a collection of data in memo= ry that will + be conveyed from a non-SMM environment in= to an SMM environment. + @param[in,out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled an= d quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quies= ced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pendi= ng and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be q= uiesced. +**/ +EFI_STATUS +EFIAPI +PchSwSmiDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo; + UINTN CpuIndex; + SW_SMI_RECORD *SwSmiRecord; + LIST_ENTRY *LinkInDb; + EFI_SMM_SW_CONTEXT SwSmiCommBuffer; + UINTN SwSmiCommBufferSize; + + SwSmiCommBufferSize =3D sizeof (EFI_SMM_SW_CONTEXT); + // + // The value in DataPort might not be accurate in multiple thread enviro= nment. + // There might be racing condition for R_PCH_IO_APM_STS port. + // Therefor, this is just for reference. + // + SwSmiCommBuffer.DataPort =3D IoRead8 (R_PCH_IO_APM_STS); + + for (CpuIndex =3D 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { + Status =3D mSmmCpuProtocol->ReadSaveState ( + mSmmCpuProtocol, + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), + EFI_SMM_SAVE_STATE_REGISTER_IO, + CpuIndex, + &SmiIoInfo + ); + // + // If this is not the SMI source, skip it. + // + if (EFI_ERROR (Status)) { + continue; + } + // + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB2)= ", skip it. + // + if ((SmiIoInfo.IoPort !=3D R_PCH_IO_APM_CNT) || + (SmiIoInfo.IoType !=3D EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) || + (SmiIoInfo.IoWidth !=3D EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8)) + { + continue; + } + // + // If the IO data is used for SmmControl protocol, skip it. + // + if (SmiIoInfo.IoData =3D=3D 0xFF) { + continue; + } + + SwSmiCommBuffer.SwSmiCpuIndex =3D CpuIndex; + SwSmiCommBuffer.CommandPort =3D (UINT8) SmiIoInfo.IoData; + + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SmiIoInfo.IoData) { + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, &SwSmiReco= rd->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize); + } + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Lin= k); + } + } + + return EFI_SUCCESS; +} + +/** + Init required protocol for Pch Sw Dispatch protocol. +**/ +VOID +PchSwDispatchInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + DATABASE_RECORD Record; + + // + // Locate PI SMM CPU protocol + // + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOI= D **)&mSmmCpuProtocol); + ASSERT_EFI_ERROR (Status); + + // + // Initialize SW SMI Callback DataBase + // + InitializeListHead (&mSwSmiCallbackDataBase); + + // + // Insert SwSmi handler to PchSmmCore database + // There will always be one SwType record in PchSmmCore database + // + ZeroMem (&Record, sizeof (DATABASE_RECORD)); + Record.Signature =3D DATABASE_RECORD_SIGNATURE; + Record.Callback =3D PchSwSmiDispatcher; + Record.ProtocolType =3D SwType; + + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof (PCH_SMM_SOURCE_DESC)); + + DispatchHandle =3D NULL; + Status =3D SmmCoreInsertRecord ( + &Record, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmSx.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm= Sx.c new file mode 100644 index 0000000000..798fb33347 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c @@ -0,0 +1,117 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sx dispatch = protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include "PchSmiHelper.h" + +extern BOOLEAN mS3SusStart; +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 (PcdProgressCodeS3SuspendEn= d) + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSxSourceDesc =3D = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_ON_SLP_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_ON_SLP_EN + } +}; + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits t= o be filled + +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT32 Pm1Cnt; + + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + + /// + /// By design, the context phase will always be ENTRY + /// + Context->Sx.Phase =3D SxEntry; + + /// + /// Map the PM1_CNT register's SLP_TYP bits to the context type + /// + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) { + case V_ACPI_IO_PM1_CNT_S0: + Context->Sx.Type =3D SxS0; + break; + + case V_ACPI_IO_PM1_CNT_S1: + Context->Sx.Type =3D SxS1; + break; + + case V_ACPI_IO_PM1_CNT_S3: + Context->Sx.Type =3D SxS3; + break; + + case V_ACPI_IO_PM1_CNT_S4: + Context->Sx.Type =3D SxS4; + break; + + case V_ACPI_IO_PM1_CNT_S5: + Context->Sx.Type =3D SxS5; + break; + + default: + ASSERT (FALSE); + break; + } +} + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->Sx.Type =3D=3D Context2->Sx.Type); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= SmmUsb.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSm= mUsb.c new file mode 100644 index 0000000000..6b23956c4a --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.= c @@ -0,0 +1,244 @@ +/** @file + File to contain all the hardware specific stuff for the Smm USB dispatch= protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include + +typedef enum { + PchUsbControllerLpc0 =3D 0, + PchUsbControllerXhci, + PchUsbControllerTypeMax +} PCH_USB_CONTROLLER_TYPE; + +typedef struct { + UINT8 Function; + UINT8 Device; + PCH_USB_CONTROLLER_TYPE UsbConType; +} PCH_USB_CONTROLLER; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb1Legacy =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb3Legacy =3D { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_EN} + }, + S_ACPI_IO_SMI_EN, + N_ACPI_IO_SMI_EN_LEGACY_USB3 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } + }, + { + { + ACPI_ADDR_TYPE, + {R_ACPI_IO_SMI_STS} + }, + S_ACPI_IO_SMI_STS, + N_ACPI_IO_SMI_STS_LEGACY_USB3 + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_USB_CONTROLLER mUsbControllersMap[] =3D= { + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerLpc0 + }, + { + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + 0xFF, // to be updated in PchSmmUsbUpdateDescriptors + PchUsbControllerXhci + } +}; + +/** + Performs update of SmmUsb descriptors with values that have to be evalua= ted during runtime. +**/ +VOID +PchSmmUsbUpdateDescriptors ( + VOID + ) +{ + // + // mUsbControllersMap + // + mUsbControllersMap[0].Function =3D LpcFuncNumber (); + mUsbControllersMap[0].Device =3D LpcDevNumber (); + mUsbControllersMap[1].Function =3D PchXhciFuncNumber (); + mUsbControllersMap[1].Device =3D PchXhciDevNumber (); +} + +/** + Find the handle that best matches the input Device Path and return the U= SB controller type + + @param[in] DevicePath Pointer to the device Path table + @param[out] Controller Returned with the USB controller type of= the input device path + + @retval EFI_SUCCESS Find the handle that best matches the in= put Device Path + @exception EFI_UNSUPPORTED Invalid device Path table or can't find = any match USB device path + PCH_USB_CONTROLLER_TYPE The USB controll= er type of the input + device path +**/ +EFI_STATUS +DevicePathToSupportedController ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT PCH_USB_CONTROLLER_TYPE *Controller + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + ACPI_HID_DEVICE_PATH *AcpiNode; + PCI_DEVICE_PATH *PciNode; + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; + UINT8 UsbIndex; + /// + /// Find the handle that best matches the Device Path. If it is only a + /// partial match the remaining part of the device path is returned in + /// RemainingDevicePath. + /// + RemaingDevicePath =3D DevicePath; + Status =3D gBS->LocateDevicePath ( + &gEfiPciRootBridgeIoProtocolGuid, + &DevicePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + DevicePath =3D RemaingDevicePath; + + /// + /// Get first node: Acpi Node + /// + AcpiNode =3D (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; + + if (AcpiNode->Header.Type !=3D ACPI_DEVICE_PATH || + AcpiNode->Header.SubType !=3D ACPI_DP || + DevicePathNodeLength (&AcpiNode->Header) !=3D sizeof (ACPI_HID_DEVIC= E_PATH) || + AcpiNode->HID !=3D EISA_PNP_ID (0x0A03) || + AcpiNode->UID !=3D 0 + ) { + return EFI_UNSUPPORTED; + } else { + /// + /// Get the next node: Pci Node + /// + RemaingDevicePath =3D NextDevicePathNode (RemaingDevicePath); + PciNode =3D (PCI_DEVICE_PATH *) RemaingDevicePath; + if (PciNode->Header.Type !=3D HARDWARE_DEVICE_PATH || + PciNode->Header.SubType !=3D HW_PCI_DP || + DevicePathNodeLength (&PciNode->Header) !=3D sizeof (PCI_DEVICE_PA= TH) + ) { + return EFI_UNSUPPORTED; + } + + for (UsbIndex =3D 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (= PCH_USB_CONTROLLER); UsbIndex++) { + if ((PciNode->Device =3D=3D mUsbControllersMap[UsbIndex].Device) && + (PciNode->Function =3D=3D mUsbControllersMap[UsbIndex].Function)= ) { + *Controller =3D mUsbControllersMap[UsbIndex].UsbConType; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; + } +} + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must b= e USB. + @param[in] SrcDesc The source description that corresponds = to the given context. + +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PCH_USB_CONTROLLER_TYPE Controller; + EFI_STATUS Status; + + Status =3D DevicePathToSupportedController (Context->Usb.Device, &Contro= ller); + /// + /// Either the device path passed in by the child is incorrect or + /// the ones stored here internally are incorrect. + /// + ASSERT_EFI_ERROR (Status); + + switch (Context->Usb.Type) { + case UsbLegacy: + switch (Controller) { + case PchUsbControllerLpc0: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof (PCH_= SMM_SOURCE_DESC)); + break; + + case PchUsbControllerXhci: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof (PCH_= SMM_SOURCE_DESC)); + break; + + default: + ASSERT (FALSE); + break; + } + break; + + case UsbWake: + ASSERT (FALSE); + break; + + default: + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= xSmmHelpers.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchxSmmHelpers.c new file mode 100644 index 0000000000..c0ce5785fd --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel= pers.c @@ -0,0 +1,682 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include +#include + +extern UINT32 mTco1StsClear; +// +// Help handle porting bit shifts to IA-64. +// +#define BIT_ZERO 0x00000001 + +/** + Publish SMI Dispatch protocols. + + +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UINTN Index; + // + // Install protocol interfaces. + // + for (Index =3D 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) { + Status =3D gSmst->SmmInstallProtocolInterface ( + &mPrivateData.InstallMultProtHandle, + mPrivateData.Protocols[Index].Guid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Protocols[Index].Protocols.Generic + ); + } + ASSERT_EFI_ERROR (Status); +} + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successful= ly. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Clear all SMIs + // + PchSmmClearSmi (); + + Status =3D PchSmmEnableGlobalSmiBit (); + ASSERT_EFI_ERROR (Status); + + // + // Be *really* sure to clear all SMIs + // + PchSmmClearSmi (); + + return EFI_SUCCESS; +} + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Set the "global smi enable" bit + // + SmiEn |=3D B_ACPI_IO_SMI_EN_GBL_SMI; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + return EFI_SUCCESS; +} + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Reset the PCH to generate subsequent SMIs + // + SmiEn |=3D B_ACPI_IO_SMI_EN_EOS; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); + + // + // Double check that the assert worked + // + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); + + // + // Return TRUE if EOS is set correctly + // + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) =3D=3D 0) { + // + // EOS was not set to a 1; this is an error + // + return FALSE; + } else { + // + // EOS was correctly set to a 1 + // + return TRUE; + } +} + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ) +{ + BOOLEAN SciEn; + UINT32 Pm1Cnt; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D B_ACPI= _IO_PM1_CNT_SCI_EN); + + return SciEn; +} + +/** + Read a specifying bit with the register + These may or may not need to change w/ the PCH version; they're highly I= A-32 dependent, though. + + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegSize; + BOOLEAN BitWasOne; + UINTN ShiftCount; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc !=3D NULL); + if (BitDesc =3D=3D NULL) { + return FALSE; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize =3D 0; + Register =3D 0; + ShiftCount =3D 0; + BitWasOne =3D FALSE; + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { + RegisterOffset =3D BitDesc->Reg.Data.acpi; + BaseAddr =3D mAcpiBaseAddr; + } else { + RegisterOffset =3D BitDesc->Reg.Data.tco; + BaseAddr =3D mTcoBaseAddr; + } + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize =3D SMM_IO_UINT8; + break; + + case 2: + RegSize =3D SMM_IO_UINT16; + break; + + case 4: + RegSize =3D SMM_IO_UINT32; + break; + + case 8: + RegSize =3D SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); + + ShiftCount =3D BitDesc->Bit; + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize =3D=3D SMM_IO_UINT64) { + RegSize =3D SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >=3D 32) { + RegisterOffset +=3D 4; + ShiftCount -=3D 32; + } + } + + Status =3D gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) !=3D 0) { + BitWasOne =3D TRUE; + } else { + BitWasOne =3D FALSE; + } + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register =3D (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio)= ; + break; + + case 2: + Register =3D (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio= ); + break; + + case 4: + Register =3D (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio= ); + break; + + case 8: + Register =3D (UINT64) MmioRead32 ((UINTN) B= itDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc->R= eg.Data.Mmio + 4); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne =3D TRUE; + } else { + BitWasOne =3D FALSE; + } + break; + + case PCIE_ADDR_TYPE: + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + Register =3D (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg); + break; + + case 2: + Register =3D (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg)= ; + break; + + case 4: + Register =3D (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg)= ; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) !=3D 0) { + BitWasOne =3D TRUE; + } else { + BitWasOne =3D FALSE; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, and it with the bit to read + // + switch (BitDesc->SizeInBytes) { + case 1: + Register =3D PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset); + break; + + case 2: + Register =3D PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset); + break; + + case 4: + Register =3D PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, Bit= Desc->Reg.Data.Pcr.Fields.Offset); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne =3D TRUE; + } else { + BitWasOne =3D FALSE; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } + + return BitWasOne; +} + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is writ= e clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT64 AndVal; + UINT64 OrVal; + UINT32 RegSize; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegisterOffset; + UINT32 BaseAddr; + UINT64 PciBaseAddress; + + ASSERT (BitDesc !=3D NULL); + if (BitDesc =3D=3D NULL) { + return; + } + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize =3D 0; + Register =3D 0; + + if (WriteClear) { + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit); + } else { + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); + } + + OrVal =3D (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case TCO_ADDR_TYPE: + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { + RegisterOffset =3D BitDesc->Reg.Data.acpi; + BaseAddr =3D mAcpiBaseAddr; + } else { + RegisterOffset =3D BitDesc->Reg.Data.tco; + BaseAddr =3D mTcoBaseAddr; + } + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + RegSize =3D SMM_IO_UINT8; + break; + + case 2: + RegSize =3D SMM_IO_UINT16; + break; + + case 4: + RegSize =3D SMM_IO_UINT32; + break; + + case 8: + RegSize =3D SMM_IO_UINT64; + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); + + // + // As current CPU Smm Io can only support at most + // 32-bit read/write,if Operation is 64 bit, + // we do a 32 bit operation according to BitDesc->Bit + // + if (RegSize =3D=3D SMM_IO_UINT64) { + RegSize =3D SMM_IO_UINT32; + // + // If the operation is for high 32 bits + // + if (BitDesc->Bit >=3D 32) { + RegisterOffset +=3D 4; + + if (WriteClear) { + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); + } else { + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); + } + + OrVal =3D LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32); + } + } + + Status =3D gSmst->SmmIo.Io.Read ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + Register &=3D AndVal; + Register |=3D OrVal; + + Status =3D gSmst->SmmIo.Io.Write ( + &gSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + break; + + case GPIO_ADDR_TYPE: + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) AndVal= , (UINT8) OrVal); + break; + + case 2: + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) AndVal= , (UINT16) OrVal); + break; + + case 4: + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) AndVal= , (UINT32) OrVal); + break; + + case 8: + Register =3D (UINT64) MmioRead32 ((UINTN) B= itDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc->R= eg.Data.Mmio + 4); + Register &=3D AndVal; + Register |=3D OrVal; + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register); + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&= Register) + 1)); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCIE_ADDR_TYPE: + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMB= ER_PCH, PciBus, PciDev, PciFun, 0); + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized -- check y= our assignments + // to bit descriptions. + // + ASSERT (FALSE); + break; + + case 1: + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, (= UINT8) OrVal); + break; + + case 2: + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal,= (UINT16) OrVal); + break; + + case 4: + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal,= (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + case PCR_ADDR_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + switch (BitDesc->SizeInBytes) { + case 1: + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) = OrVal); + break; + + case 2: + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) = OrVal); + break; + + case 4: + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pi= d, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) = OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE); + break; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE); + break; + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pch= xSmmHelpers.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/= PchxSmmHelpers.h new file mode 100644 index 0000000000..998b38e159 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHel= pers.h @@ -0,0 +1,107 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _PCHX_SMM_HELPERS_H_ +#define _PCHX_SMM_HELPERS_H_ + +#include "PchSmm.h" + +/** + Initialize bits that aren't necessarily related to an SMI source. + + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successful= ly. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ); + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ); + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ); + +/** + Set the SMI EOS bit after all SMI source have been processed. + + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ); + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ); + +/** + Read a specifying bit with the register + + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc + ); + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register addres= s, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is writ= e clear + +**/ +VOID +WriteBitDesc ( + CONST PCH_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite, + CONST BOOLEAN WriteClear + ); + +#endif diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Pci= eSmmClient.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/P= cieSmmClient.c new file mode 100644 index 0000000000..6d210f671b --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PcieSmmCli= ent.c @@ -0,0 +1,38 @@ +/** @file + This function handle the register/unregister of PCH PCIe specific SMI ev= ents. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include "PchSmmHelpers.h" +#include +#include +#include +#include +#include +#include +#include + +extern UINT32 mNumOfRootPorts; + +/** + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port ph= ysical Number + + @param[in] RpNumber Root port physical number. (0-based) + @param[out] RpDev Return corresponding root port device = number. + @param[out] RpFun Return corresponding root port functio= n number. +**/ +VOID +GetPcieRpDevFun ( + IN UINTN RpIndex, + OUT UINTN *RpDev, + OUT UINTN *RpFun + ) +{ + if (RpIndex >=3D CpuRpIndex0 && RpIndex <=3D CpuRpIndex3) { + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun); + } else { + *RpDev =3D PchPcieRpDevNumber (RpIndex); + *RpFun =3D PchPcieRpFuncNumber (RpIndex); + } +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/Smm= GlobalsPch.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/S= mmGlobalsPch.c new file mode 100644 index 0000000000..f66079884f --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/SmmGlobals= Pch.c @@ -0,0 +1,20 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include + +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mTco1StsClear =3D + ( + B_TCO_IO_TCO1_STS_DMISERR | + B_TCO_IO_TCO1_STS_DMISMI | + B_TCO_IO_TCO1_STS_DMISCI | + B_TCO_IO_TCO1_STS_BIOSWR | + B_TCO_IO_TCO1_STS_NEWCENTURY | + B_TCO_IO_TCO1_STS_TIMEOUT | + B_TCO_IO_TCO1_STS_TCO_INT | + B_TCO_IO_TCO1_STS_SW_TCO_SMI + ); diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControl.inf b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/= SmmControl.inf new file mode 100644 index 0000000000..d73c12f964 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= l.inf @@ -0,0 +1,53 @@ +## @file +# Component description file for SmmControl module +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D SmmControl +FILE_GUID =3D A0BAD9F7-AB78-491b-B583-C52B7F84B9E0 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_RUNTIME_DRIVER +ENTRY_POINT =3D SmmControlDriverEntryInit +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + + + +[LibraryClasses] +IoLib +UefiDriverEntryPoint +DebugLib +UefiBootServicesTableLib +UefiRuntimeServicesTableLib +PmcLib +GpioLib + + +[Packages] +MdePkg/MdePkg.dec +AlderlakeSiliconPkg/SiPkg.dec + + +[Sources] +SmmControlDriver.h +SmmControlDriver.c + + +[Protocols] +gEfiSmmControl2ProtocolGuid ## PRODUCES + + +[Guids] +gEfiEventVirtualAddressChangeGuid + + +[Depex] +TRUE diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControlDriver.c b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/Runtime= Dxe/SmmControlDriver.c new file mode 100644 index 0000000000..8864d18787 --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= lDriver.c @@ -0,0 +1,338 @@ +/** @file + This is the driver that publishes the SMM Control Protocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SmmControlDriver.h" + +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase; + +/** + Fixup internal data pointers so that the services can be called in virtu= al mode. + + @param[in] Event The event registered. + @param[in] Context Event context. + +**/ +VOID +EFIAPI +SmmControlVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger)); + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear)); +} + +/** + SmmControl DXE RUNTIME Module Entry Point\n + - Introduction\n + The SmmControl module is a DXE RUNTIME driver that provides a standard= way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been program= med. + If SmmControl Runtime DXE driver is run before Status Code Runtime P= rotocol + is installed and there is the need to use Status code in the driver,= it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dep= endency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specificat= ion. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented= in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM C= ontrol Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n")); + + // + // Get the Power Management I/O space base address. We assume that + // this base address has already been programmed if this driver is + // being run. + // + mABase =3D PmcGetAcpiBase (); + + Status =3D EFI_SUCCESS; + if (mABase !=3D 0) { + // + // Install the instance of the protocol + // + mSmmControl.Signature =3D SMM_CONTROL_PRIVATE_DA= TA_SIGNATURE; + mSmmControl.Handle =3D ImageHandle; + + mSmmControl.SmmControl.Trigger =3D Activate; + mSmmControl.SmmControl.Clear =3D Deactivate; + mSmmControl.SmmControl.MinimumTriggerPeriod =3D 0; + + // + // Install our protocol interfaces on the device's handle + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &mSmmControl.Handle, + &gEfiSmmControl2ProtocolGuid, + &mSmmControl.SmmControl, + NULL + ); + } else { + Status =3D EFI_DEVICE_ERROR; + return Status; + } + + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n")); + + return Status; +} + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI = command port + @param[in] Data The value to be set on the software SMI = data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ) +{ + UINT32 OutputData; + UINT32 OutputPort; + + // + // Enable the APMC SMI + // + OutputPort =3D mABase + R_ACPI_IO_SMI_EN; + OutputData =3D IoRead32 ((UINTN) OutputPort); + OutputData |=3D (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI); + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + OutputPort =3D R_PCH_IO_APM_STS; + OutputData =3D Data; + + // + // Write data to APM DATA PORT + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + OutputPort =3D R_PCH_IO_APM_CNT; + OutputData =3D Command; + + // + // Generate the APMC SMI + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + + return EFI_SUCCESS; +} + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 OutputData; + UINT32 OutputPort; + + Status =3D EFI_SUCCESS; + + // + // Clear the Power Button Override Status Bit, it gates EOS from being s= et. + // + OutputPort =3D mABase + R_ACPI_IO_PM1_STS; + OutputData =3D B_ACPI_IO_PM1_STS_PRBTNOR; + DEBUG ( + (DEBUG_VERBOSE, + "The PM1 Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite16 ( + (UINTN) OutputPort, + (UINT16) (OutputData) + ); + + // + // Clear the APM SMI Status Bit + // + OutputPort =3D mABase + R_ACPI_IO_SMI_STS; + OutputData =3D B_ACPI_IO_SMI_STS_APM; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // Set the EOS Bit + // + OutputPort =3D mABase + R_ACPI_IO_SMI_EN; + OutputData =3D IoRead32 ((UINTN) OutputPort); + OutputData |=3D B_ACPI_IO_SMI_EN_EOS; + DEBUG ( + (DEBUG_VERBOSE, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // There is no need to read EOS back and check if it is set. + // This can lead to a reading of zero if an SMI occurs right after the S= MI_EN port read + // but before the data is returned to the CPU. + // SMM Dispatcher should make sure that EOS is set after all SMI sources= are processed. + // + return Status; +} + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol insta= nce + @param[in, out] CommandPort The buffer contains data to the co= mmand port + @param[in, out] DataPort The buffer contains data to the da= ta port + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the opera= tion + @retval EFI_INVALID_PARAMETER Some parameter value passed is not= supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This, + IN OUT UINT8 *CommandPort = OPTIONAL, + IN OUT UINT8 *DataPort = OPTIONAL, + IN BOOLEAN Periodic = OPTIONAL, + IN UINTN ActivationInterval= OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 Command; + UINT8 Data; + + if (Periodic) { + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Extract the values from CommandPort and DataPort + // + if (CommandPort =3D=3D NULL) { + Command =3D 0xFF; + } else { + Command =3D *CommandPort; + } + + if (DataPort =3D=3D NULL) { + Data =3D 0x00; + } else { + Data =3D *DataPort; + } + + // + // Clear any pending the APM SMI + // + Status =3D SmmClear (); + if (EFI_ERROR (Status)) { + return Status; + } + + return SmmTrigger (Command, Data); +} + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not suppo= rted +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + return SmmClear (); +} diff --git a/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/Sm= mControlDriver.h b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/Runtime= Dxe/SmmControlDriver.h new file mode 100644 index 0000000000..a366de7d5e --- /dev/null +++ b/Silicon/Intel/AlderlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContro= lDriver.h @@ -0,0 +1,122 @@ +/** @file + Header file for SMM Control Driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#ifndef _SMM_CONTROL_DRIVER_H_ +#define _SMM_CONTROL_DRIVER_H_ + +#include + + +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', '= c') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SMM_CONTROL2_PROTOCOL SmmControl; +} SMM_CONTROL_PRIVATE_DATA; + +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_D= ATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE) + +// +// Prototypes +// + +/** + SmmControl DXE RUNTIME Module Entry Point\n + - Introduction\n + The SmmControl module is a DXE RUNTIME driver that provides a standard= way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been program= med. + If SmmControl Runtime DXE driver is run before Status Code Runtime P= rotocol + is installed and there is the need to use Status code in the driver,= it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dep= endency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specificat= ion. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented= in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM C= ontrol Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Trigger the software SMI + + @param[in] Command The value to be set on the software SMI = command port + @param[in] Data The value to be set on the software SMI = data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Command, + IN UINT8 Data + ); + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ); + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol insta= nce + @param[in, out] ArgumentBuffer The buffer of argument + @param[in, out] ArgumentBufferSize The size of the argument buffer + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the opera= tion + @retval EFI_INVALID_PARAMETER Some parameter value passed is not= supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *ArgumentBuffer OPTIONAL, + IN OUT UINT8 *ArgumentBufferSize OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ); + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not suppo= rted +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ); +#endif --=20 2.36.1.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107784): https://edk2.groups.io/g/devel/message/107784 Mute This Topic: https://groups.io/mt/100551004/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-