From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=40.107.3.79; helo=eur03-am5-obe.outbound.protection.outlook.com; envelope-from=achin.gupta@arm.com; receiver=edk2-devel@lists.01.org Received: from EUR03-AM5-obe.outbound.protection.outlook.com (mail-eopbgr30079.outbound.protection.outlook.com [40.107.3.79]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 62ABC203B8BFE for ; Mon, 30 Apr 2018 12:18:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=JvwkqbzVubiqYkvho4GgtXy9ABM/wia5HEl6CRldV9U=; b=XF5kRKiw3hcuAggWt9Jkf9JSzYpM0kgBkYiW5iV+yuQPSZPW/1BYx6DnGmg27j9QKdQTkhzILyFr1NlcBz5YtHPUMc4ZrfETWaqZVsoz2Ir+rKNmEPwtWaqyQMHvpTb4RCvGm16sGUMEEDO6o5/+qz2KQoLvByaOUG02Br0rSiY= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Achin.Gupta@arm.com; Received: from e104320-lin (217.140.96.140) by VI1PR08MB2991.eurprd08.prod.outlook.com (2603:10a6:803:44::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.715.20; Mon, 30 Apr 2018 19:18:21 +0000 Date: Mon, 30 Apr 2018 20:19:43 +0100 From: Achin Gupta To: Supreeth Venkatesh Cc: edk2-devel@lists.01.org, michael.d.kinney@intel.com, liming.gao@intel.com, jiewen.yao@intel.com, leif.lindholm@linaro.org, ard.biesheuvel@linaro.org, nd@arm.com Message-ID: <20180430191942.GX663@e104320-lin> References: <20180406144223.10931-1-supreeth.venkatesh@arm.com> <20180406144223.10931-14-supreeth.venkatesh@arm.com> MIME-Version: 1.0 In-Reply-To: <20180406144223.10931-14-supreeth.venkatesh@arm.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-Originating-IP: [217.140.96.140] X-ClientProxiedBy: DB6PR07CA0157.eurprd07.prod.outlook.com (2603:10a6:6:43::11) To VI1PR08MB2991.eurprd08.prod.outlook.com (2603:10a6:803:44::21) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(48565401081)(5600026)(2017052603328)(7153060)(7193020); SRVR:VI1PR08MB2991; X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 3:3WuqD/Yy9pRwIjdERwZAwwL/uoNGvT27CgqKIv3ESE9k8eS7+/NLfwPuT8Y3CgPsGeite+xr80G4Cmp1kDngMuRmVsdaVWFw/q2lOEpvn+neA/aM7KlR+HkCljkLOq9yyGxtms11Yb0RV448oOtyV61yF/n5q2bxMOIsv0A6SJWqiqchzzq7iZiHv1AK9kxrS0ajRU6ctLsEsHgFK0/flIR4vtAsH7VZlPadLf2djRy8I0ys8jNZf2QAHl55NszR; 25:kYTk7AmXMb39F6SIr+CXkWHzpBofZyYleuEuzYxWVOUsLu/ajttGQXtxwdiZGVoUDeElwl/n3cWcXYxrxErFpPWNc2STiFe8ayluqa4aeCPRYZsjy3RKn7nNNKYqejBvWjSCL7KQq5oxCp3t1kVJyqngiPrPHAi+XzvynMBagv8GdtbeAFw/7PTsG47H0MbGejgj8ktMP3ihq9E/cT7wduz9PJRE/E9/c0Wv150i83qHZ6SQLHj/zNZRhqzSWsjLaDAw8TOHyKQBrKFJEjszuczaELZK1gl4iSyb+1RRYacAYT+WFbeVuL+1bouVudR1gwvAsXood+So3QyJ52K3Rg==; 31:tEz2IMPUEWo3fygtB7Lr8krM1Su8xEyn8J0FayTJT8a7UaDpPslA93jxY/0K/jFLqNqLzfXGKMZEoANhi6MSgYI4KLdekkQ52SX4qXV+XlxBjyqBi6tVjw15z/h4G/Ddeusrrn1JFLNAlEKLiAhVXWQD7tciwiVr+pNZ/lniHdxjkcKPstlFsD6Df3DA0vZJWSOV5o8NwZClKqAO06qA4/5d8eEym+189uyfBeR3v08= X-MS-TrafficTypeDiagnostic: VI1PR08MB2991: NoDisclaimer: True X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 20:afQQbjlK+hseSgoJzi9njcaDXIhI2Hqw471xtxC/EpQrWrXaIfvaHErr9gZOlrxgZTFaVQX+CXvi7DFWErRcf1DbKR7K/ktqKQ88/rYGHCfEdSvc8MFwpceTKnwEoOm9+3jVYjN5Xg2vF06lub5vHLRZWN0+GS0BJXm8XILgjN2uzgk6tOFBXw01+83TZDoJMPhW3DOF7L6RxjkCIEapWZ+t4hrzu1k+ciaPPxQ0Tl5Po8mdF/gxVsagbV5WxmqN; 4:6iLR0cCaJyhqRR0ujXLRDufLxv5+aXJMvBO/r+fIrw9IO09pXBZCBOpqXGVxu5Op3l2N2dtM1Gw8EWNM1849vFOoFl4PRwmvw5SxCqmH27jmOP/9IufZTcBnrk38ovl89zzULEstJehnHDlvG1t4AvnkIiPmTalzJtSEQqCHTeID0rg9BmphGSbGNtZ+xAoiWqd4PnMn5+SdwkRqtosBasaY9YmG02NmDt/n0RWDsP+q9ZA2oidjUgudmrDNSp3YuK7/i57Azf73FM7JKwq8+0DDM/tWSf5c/2QiofGqiZsBi0TooAVeAHfLCCZfqM/+Zfl/SOrWeW9i4L+//dL4SS3cKBDA+L03hsm8mzdrLIg= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(180628864354917)(788757137089); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(3231254)(944501410)(52105095)(3002001)(10201501046)(93006095)(93001095)(6055026)(6041310)(20161123562045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123558120)(20161123564045)(20161123560045)(6072148)(201708071742011); SRVR:VI1PR08MB2991; BCL:0; PCL:0; RULEID:; SRVR:VI1PR08MB2991; X-Forefront-PRVS: 0658BAF71F X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6029001)(39860400002)(346002)(39380400002)(376002)(366004)(396003)(50944005)(199004)(189003)(476003)(11346002)(6636002)(956004)(229853002)(76176011)(6116002)(3846002)(66066001)(6496006)(23726003)(446003)(52116002)(1076002)(72206003)(47776003)(6666003)(966005)(5660300001)(316002)(33716001)(58126008)(26005)(86362001)(478600001)(16586007)(97736004)(81156014)(81166006)(8676002)(8936002)(16200700003)(53946003)(25786009)(68736007)(6862004)(6246003)(53936002)(9686003)(33656002)(486006)(55016002)(6306002)(44832011)(53376002)(33896004)(15188155005)(2906002)(16799955002)(386003)(7736002)(50466002)(305945005)(59450400001)(105586002)(106356001)(16526019)(4326008)(18370500001)(107986001)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR08MB2991; H:e104320-lin; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR08MB2991; 23:hS/Owluks9TecnMmI60fEfYmMckPDuKpghJdKV7v1?= =?us-ascii?Q?tekmC3fx39vPp4+9PRZoQxyo3oC2zdgkM6DpukUubnUQHWu9uWjbn0trQ2AO?= =?us-ascii?Q?OGwmfDLzNJCMnQGyv4lCxlFD8GaeULY0Jl2T9HEdGzw9aauoGkAQItyoXxr0?= =?us-ascii?Q?9J1afvZRX5FBS7E2e3Xj6WeXoa2uWN7xZ5QklDxuax7vrFcL31gJpOUhBiY2?= =?us-ascii?Q?CTVKrOh1+AGP4A5uMXdImJEUJuKIjeJDO/I8OYD0lwJZ3H9hvndH08tl3Coi?= =?us-ascii?Q?wnqo/AMUqOzdNtx3ZKfZ8ekqlnSHy/YZEvynkzsV+/Y3rvivOBJjEMG++CaV?= =?us-ascii?Q?LAstRSSr525ieCPwKe+jzKXEmvGv8VyKPE8jea78XihwI90GHnJt+nLhffeX?= =?us-ascii?Q?LvOUroaJ+fyHr/vKNM/YN+K4f8kw/Djo2qxb9c5mrRXsWhK2jFD3MMF+gxlU?= =?us-ascii?Q?dpXyMWRANjMhxf+QCMHXX1Uo8stwAw4WddiqMNKwdoxoOcDKHzVAbhNHNsa1?= =?us-ascii?Q?2cp8GXt3LzOT1R87ryQnBtuQDerQlxBHWfKFdbvaNTCf0Hss+tSr3/BLeF2O?= =?us-ascii?Q?sG8EfTOT7zOwMuqbUrniSYzbIkoAYWnzoJQ3o058CMd1fMbZ9biJv4yK3YOJ?= =?us-ascii?Q?4cJIiJUtZ12pTpXGNuwhbmy1g2NwQhpPo5cyzHvoAA5mhIQJQQdQjYrxm11E?= =?us-ascii?Q?VkdgSep5m5/liNwmKANskgY191hd+lQ6/wl5ash9/cD+sTB6qRekubCVGFGa?= =?us-ascii?Q?hjGjVYDhCsgf0tbegtsQUCREQEgYA/PbK/2OJnQPED+hUbaLUyo45JsH1U68?= =?us-ascii?Q?cpBuwbORs02+reEwNa5j+qbmqQUlvmL/opKRwQDU/bXZFmpQUvxomJvwlui0?= =?us-ascii?Q?w2qUdtvtabb+DW/mPQMJ6R9uFfz/7D+28NrY3cDECtfG8gH9CkG9v+h0Lesj?= =?us-ascii?Q?rR/0DIrPSsHdi+9NB3VAw8afMXOIhkiZbMoPIfe596hCfQnSpavgy3czMWRY?= =?us-ascii?Q?7zsNRG9XnGS9NVk3EeAO92Khy86o2VBY0SlPyjR0m5eQy7E2cEEfxM4e0SQw?= =?us-ascii?Q?dYKRbrvbvMgfOeUNKnVfVmaWwwx+k9i9Q1bOyQpokidlKCfmr6Ec7jFO5y9g?= =?us-ascii?Q?SEkNmQCq6DqsiI460rQ0Z1IR5EzqU2hhka8wdOzS+tBnrr0cKvQOUzAfuNiA?= =?us-ascii?Q?rGih6Ic69xnK7tPQua7GyoC6FY50AQMZKYCWj256VAXysRVRW695R6lBr6Pl?= =?us-ascii?Q?X896KCbCZVusKWiifcX/iuvcAkLQCycuFWeEGIFYyygbvvBS6nvA5sueFwa6?= =?us-ascii?Q?bX5Ia1yjUEioy1+B+dXdH5qAljsFXcZq7EZhKn3aYLm/JR7L6nUQgizDnXW3?= =?us-ascii?Q?psSJTjXL4R9rVVyT/LySgUNKCfBLNqyR3QxenK4f1Uc2hHTgXyQ03g/AK8WB?= =?us-ascii?Q?BUl+UlQBzecqcmVjwrkFJ0KJFIyDwHxU3RR0x3PxDrrWqNN50EK653BGR1jY?= =?us-ascii?Q?cF4+HCLhKsH5sP4GuyK4mLhNDGBTejUa5aFN5JJZM5M8DT1HFvfBzkful4Vd?= =?us-ascii?Q?3dKjiG9fuvisDejaCtcV7EnbTjzTkkqEEsquz8=3D?= X-Microsoft-Antispam-Message-Info: A5ZP6IALlK7/33NyS5akZZt/1+RhS4AqIoE8TMTdDgOwag0DOTWaSt+8Gx9ljVcH2W/70tBItistfkF7R9aKMGbJMA4HOfM+zx48o1dsOLDTUpT6UjWtwY0diRAPaXpUl3Fdpm/D5IjxGWTvYeQlQSXeW2eqUqehEL4lsxq2pswmsOHVf2w3vt7na5rMJROd X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 6:cmYdpWvtUOenn1q3WEcBGlOFZOTf0sPzYw+aaszkhac23EHCQJICfeH3NDs7q13ikjjl9RVytNejBdT2j4bCmxGwa/oSk4ksWW0rNuNH3pBm+E264XcvdyqIhbPhnoBKsHmKYQ71s4+UWXpTIuhjX7FmVPeSRzBlYVUqhpFIiVcNqcBe5rswOtSowtDBSH54l9vxKRMh7QAlfCx0/vXd0FfjwnGJRECEsYSinBxArdPer+LjdCSR2buzDkfLpAu89kyogmMZCL9D3XyhwYhddBdwOcuN/IRBJD/R/tp53VkeCKW72NfFS3RiyeviYd8XAcb9FKdZdJfUiYNB6JRVs9Py0hDBWqGMCO5C4JsAv1sj9YnTJGZaHVtdEFvanCUb3edg4jZG0AKOhrvU7TqJZUqGnY2rMoY3JFwWr37LlJa/OojT3g4hgi6G+NQ0SUhR7bCIkgmqI5Z8pGki56naKA==; 5:3QUe7P1qbFTBjKMTdWgWSfgxOmVAtcvq939/LmrgYX691kA5nC9ERjcs1impjn1u6vUk2H2JWwcuLRbNOyo/DCDcocw63LcJy1VlBPHvpbH8bdv3ixby6qOFxu5+0FdlRlZvKYPDDnuvKShIaghAZyMPFbRT7p/oburF+xim+g0=; 24:mHkIV2A22MF6MKHZZm5S9TSsBNanmEeSxO5ePgkXz2ClEdhzLtZidz01brNwJoGPyjHO4x/ch+hb+y14w1oVVRP/67Xn/H/6eGRiVotdMPQ= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 7:dX5UJKcROIBjwpumlyUjffNTWIjHGOUsy5W7+TQhoLoaMB/p9qv/5AtA/9lRc/AdeK+gzUsa8H5oMyr/x4fB/ZB7E9l+6BGRIhl3iw/+uqXEwuObssSv9glepptmmdTTKtKwOo8VsKbYTvcywi5mwQEvf8hlbbp373Pe/asiNiqshjwo17hK3lzP4WiEZ6qEZ8VF8n4bbHzZn8pZfuzWA4HJjHoltPTkaU7lBV/upqCVT6jYyvLK6XwMsuMdZ8ET X-MS-Office365-Filtering-Correlation-Id: d11b63b3-a603-47e4-b746-08d5aecf23b3 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2018 19:18:21.6987 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d11b63b3-a603-47e4-b746-08d5aecf23b3 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR08MB2991 Subject: Re: [PATCH v1 13/18] StandaloneMmPkg/Core: Implementation of Standalone MM Core Module. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Apr 2018 19:18:33 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi Supreeth, I think it is worth adding a signed off by Jiewen since he originally contributed the code and it has not changed much since. Please update the correct year in the copyright headers too. Acked-by: Achin Gupta cheers, Achin On Fri, Apr 06, 2018 at 03:42:18PM +0100, Supreeth Venkatesh wrote: > Management Mode (MM) is a generic term used to describe a secure > execution environment provided by the CPU and related silicon that is > entered when the CPU detects a MMI. For x86 systems, this can be > implemented with System Management Mode (SMM). For ARM systems, this can > be implemented with TrustZone (TZ). > A MMI can be a CPU instruction or interrupt. Upon detection of a MMI, a > CPU will jump to the MM Entry Point and save some portion of its state > (the "save state") such that execution can be resumed. > The MMI can be generated synchronously by software or asynchronously by > a hardware event. Each MMI source can be detected, cleared and disabled. > Some systems provide for special memory (Management Mode RAM or MMRAM) > which is set aside for software running in MM. Usually the MMRAM is > hidden during normal CPU execution, but this is not required. Usually, > after MMRAM is hidden it cannot be exposed until the next system reset. > > The MM Core Interface Specification describes three pieces of the PI > Management Mode architecture: > 1. MM Dispatch > During DXE, the DXE Foundation works with the MM Foundation to > schedule MM drivers for execution in the discovered firmware volumes. > 2. MM Initialization > MM related code opens MMRAM, creates the MMRAM memory map, and > launches the MM Foundation, which provides the necessary services to > launch MM-related drivers. Then, sometime before boot, MMRAM is > closed and locked. This piece may be completed during the > SEC, PEI or DXE phases. > 3. MMI Management > When an MMI generated, the MM environment is created and then the MMI > > sources are detected and MMI handlers called. > > This patch implements the MM Core. > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Achin Gupta > Signed-off-by: Supreeth Venkatesh > --- > StandaloneMmPkg/Core/Dependency.c | 389 +++++++ > StandaloneMmPkg/Core/Dispatcher.c | 1071 ++++++++++++++++++++ > StandaloneMmPkg/Core/FwVol.c | 104 ++ > StandaloneMmPkg/Core/Handle.c | 533 ++++++++++ > StandaloneMmPkg/Core/InstallConfigurationTable.c | 178 ++++ > StandaloneMmPkg/Core/Locate.c | 496 +++++++++ > StandaloneMmPkg/Core/Mmi.c | 337 ++++++ > StandaloneMmPkg/Core/Notify.c | 203 ++++ > StandaloneMmPkg/Core/Page.c | 384 +++++++ > StandaloneMmPkg/Core/Pool.c | 287 ++++++ > StandaloneMmPkg/Core/StandaloneMmCore.c | 708 +++++++++++++ > StandaloneMmPkg/Core/StandaloneMmCore.h | 903 +++++++++++++++++ > StandaloneMmPkg/Core/StandaloneMmCore.inf | 80 ++ > StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h | 66 ++ > StandaloneMmPkg/Include/Guid/MmFvDispatch.h | 38 + > StandaloneMmPkg/Include/StandaloneMm.h | 36 + > 16 files changed, 5813 insertions(+) > create mode 100644 StandaloneMmPkg/Core/Dependency.c > create mode 100644 StandaloneMmPkg/Core/Dispatcher.c > create mode 100644 StandaloneMmPkg/Core/FwVol.c > create mode 100644 StandaloneMmPkg/Core/Handle.c > create mode 100644 StandaloneMmPkg/Core/InstallConfigurationTable.c > create mode 100644 StandaloneMmPkg/Core/Locate.c > create mode 100644 StandaloneMmPkg/Core/Mmi.c > create mode 100644 StandaloneMmPkg/Core/Notify.c > create mode 100644 StandaloneMmPkg/Core/Page.c > create mode 100644 StandaloneMmPkg/Core/Pool.c > create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.c > create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.h > create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.inf > create mode 100644 StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h > create mode 100644 StandaloneMmPkg/Include/Guid/MmFvDispatch.h > create mode 100644 StandaloneMmPkg/Include/StandaloneMm.h > > diff --git a/StandaloneMmPkg/Core/Dependency.c b/StandaloneMmPkg/Core/Dependency.c > new file mode 100644 > index 0000000000..e501369130 > --- /dev/null > +++ b/StandaloneMmPkg/Core/Dependency.c > @@ -0,0 +1,389 @@ > +/** @file > + MM Driver Dispatcher Dependency Evaluator > + > + This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine > + if a driver can be scheduled for execution. The criteria for > + schedulability is that the dependency expression is satisfied. > + > + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +/// > +/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression > +/// to save time. A EFI_DEP_PUSH is evaluated one an > +/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2 > +/// Driver Execution Environment Core Interface use 0xff > +/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be > +/// defined to a new value that is not conflicting with PI spec. > +/// > +#define EFI_DEP_REPLACE_TRUE 0xff > + > +/// > +/// Define the initial size of the dependency expression evaluation stack > +/// > +#define DEPEX_STACK_SIZE_INCREMENT 0x1000 > + > +// > +// Global stack used to evaluate dependency expressions > +// > +BOOLEAN *mDepexEvaluationStack = NULL; > +BOOLEAN *mDepexEvaluationStackEnd = NULL; > +BOOLEAN *mDepexEvaluationStackPointer = NULL; > + > +/** > + Grow size of the Depex stack > + > + @retval EFI_SUCCESS Stack successfully growed. > + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. > + > +**/ > +EFI_STATUS > +GrowDepexStack ( > + VOID > + ) > +{ > + BOOLEAN *NewStack; > + UINTN Size; > + > + Size = DEPEX_STACK_SIZE_INCREMENT; > + if (mDepexEvaluationStack != NULL) { > + Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); > + } > + > + NewStack = AllocatePool (Size * sizeof (BOOLEAN)); > + if (NewStack == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (mDepexEvaluationStack != NULL) { > + // > + // Copy to Old Stack to the New Stack > + // > + CopyMem ( > + NewStack, > + mDepexEvaluationStack, > + (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN) > + ); > + > + // > + // Free The Old Stack > + // > + FreePool (mDepexEvaluationStack); > + } > + > + // > + // Make the Stack pointer point to the old data in the new stack > + // > + mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack); > + mDepexEvaluationStack = NewStack; > + mDepexEvaluationStackEnd = NewStack + Size; > + > + return EFI_SUCCESS; > +} > + > +/** > + Push an element onto the Boolean Stack. > + > + @param Value BOOLEAN to push. > + > + @retval EFI_SUCCESS The value was pushed onto the stack. > + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack. > + > +**/ > +EFI_STATUS > +PushBool ( > + IN BOOLEAN Value > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Check for a stack overflow condition > + // > + if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) { > + // > + // Grow the stack > + // > + Status = GrowDepexStack (); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } > + > + // > + // Push the item onto the stack > + // > + *mDepexEvaluationStackPointer = Value; > + mDepexEvaluationStackPointer++; > + > + return EFI_SUCCESS; > +} > + > +/** > + Pop an element from the Boolean stack. > + > + @param Value BOOLEAN to pop. > + > + @retval EFI_SUCCESS The value was popped onto the stack. > + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack. > + > +**/ > +EFI_STATUS > +PopBool ( > + OUT BOOLEAN *Value > + ) > +{ > + // > + // Check for a stack underflow condition > + // > + if (mDepexEvaluationStackPointer == mDepexEvaluationStack) { > + return EFI_ACCESS_DENIED; > + } > + > + // > + // Pop the item off the stack > + // > + mDepexEvaluationStackPointer--; > + *Value = *mDepexEvaluationStackPointer; > + return EFI_SUCCESS; > +} > + > +/** > + This is the POSTFIX version of the dependency evaluator. This code does > + not need to handle Before or After, as it is not valid to call this > + routine in this case. POSTFIX means all the math is done on top of the stack. > + > + @param DriverEntry DriverEntry element to update. > + > + @retval TRUE If driver is ready to run. > + @retval FALSE If driver is not ready to run or some fatal error > + was found. > + > +**/ > +BOOLEAN > +MmIsSchedulable ( > + IN EFI_MM_DRIVER_ENTRY *DriverEntry > + ) > +{ > + EFI_STATUS Status; > + UINT8 *Iterator; > + BOOLEAN Operator; > + BOOLEAN Operator2; > + EFI_GUID DriverGuid; > + VOID *Interface; > + > + Operator = FALSE; > + Operator2 = FALSE; > + > + if (DriverEntry->After || DriverEntry->Before) { > + // > + // If Before or After Depex skip as MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter () > + // processes them. > + // > + return FALSE; > + } > + > + DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); > + > + if (DriverEntry->Depex == NULL) { > + // > + // A NULL Depex means that the MM driver is not built correctly. > + // All MM drivers must have a valid depex expressiion. > + // > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Depex is empty)\n")); > + ASSERT (FALSE); > + return FALSE; > + } > + > + // > + // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by > + // incorrectly formed DEPEX expressions > + // > + mDepexEvaluationStackPointer = mDepexEvaluationStack; > + > + > + Iterator = DriverEntry->Depex; > + > + while (TRUE) { > + // > + // Check to see if we are attempting to fetch dependency expression instructions > + // past the end of the dependency expression. > + // > + if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n")); > + return FALSE; > + } > + > + // > + // Look at the opcode of the dependency expression instruction. > + // > + switch (*Iterator) { > + case EFI_DEP_BEFORE: > + case EFI_DEP_AFTER: > + // > + // For a well-formed Dependency Expression, the code should never get here. > + // The BEFORE and AFTER are processed prior to this routine's invocation. > + // If the code flow arrives at this point, there was a BEFORE or AFTER > + // that were not the first opcodes. > + // > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n")); > + ASSERT (FALSE); > + > + case EFI_DEP_PUSH: > + // > + // Push operator is followed by a GUID. Test to see if the GUID protocol > + // is installed and push the boolean result on the stack. > + // > + CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID)); > + > + Status = MmLocateProtocol (&DriverGuid, NULL, &Interface); > + if (EFI_ERROR (Status) && (mEfiSystemTable != NULL)) { > + // > + // For MM Driver, it may depend on uefi protocols > + // > + Status = mEfiSystemTable->BootServices->LocateProtocol (&DriverGuid, NULL, &Interface); > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid)); > + Status = PushBool (FALSE); > + } else { > + DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid)); > + *Iterator = EFI_DEP_REPLACE_TRUE; > + Status = PushBool (TRUE); > + } > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Iterator += sizeof (EFI_GUID); > + break; > + > + case EFI_DEP_AND: > + DEBUG ((DEBUG_DISPATCH, " AND\n")); > + Status = PopBool (&Operator); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Status = PopBool (&Operator2); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Status = PushBool ((BOOLEAN)(Operator && Operator2)); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + break; > + > + case EFI_DEP_OR: > + DEBUG ((DEBUG_DISPATCH, " OR\n")); > + Status = PopBool (&Operator); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Status = PopBool (&Operator2); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Status = PushBool ((BOOLEAN)(Operator || Operator2)); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + break; > + > + case EFI_DEP_NOT: > + DEBUG ((DEBUG_DISPATCH, " NOT\n")); > + Status = PopBool (&Operator); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Status = PushBool ((BOOLEAN)(!Operator)); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + break; > + > + case EFI_DEP_TRUE: > + DEBUG ((DEBUG_DISPATCH, " TRUE\n")); > + Status = PushBool (TRUE); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + break; > + > + case EFI_DEP_FALSE: > + DEBUG ((DEBUG_DISPATCH, " FALSE\n")); > + Status = PushBool (FALSE); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + break; > + > + case EFI_DEP_END: > + DEBUG ((DEBUG_DISPATCH, " END\n")); > + Status = PopBool (&Operator); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE")); > + return Operator; > + > + case EFI_DEP_REPLACE_TRUE: > + CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID)); > + DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid)); > + Status = PushBool (TRUE); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n")); > + return FALSE; > + } > + > + Iterator += sizeof (EFI_GUID); > + break; > + > + default: > + DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n")); > + goto Done; > + } > + > + // > + // Skip over the Dependency Op Code we just processed in the switch. > + // The math is done out of order, but it should not matter. That is > + // we may add in the sizeof (EFI_GUID) before we account for the OP Code. > + // This is not an issue, since we just need the correct end result. You > + // need to be careful using Iterator in the loop as it's intermediate value > + // may be strange. > + // > + Iterator++; > + } > + > +Done: > + return FALSE; > +} > diff --git a/StandaloneMmPkg/Core/Dispatcher.c b/StandaloneMmPkg/Core/Dispatcher.c > new file mode 100644 > index 0000000000..af18fa7eaa > --- /dev/null > +++ b/StandaloneMmPkg/Core/Dispatcher.c > @@ -0,0 +1,1071 @@ > +/** @file > + MM Driver Dispatcher. > + > + Step #1 - When a FV protocol is added to the system every driver in the FV > + is added to the mDiscoveredList. The Before, and After Depex are > + pre-processed as drivers are added to the mDiscoveredList. If an Apriori > + file exists in the FV those drivers are addeded to the > + mScheduledQueue. The mFvHandleList is used to make sure a > + FV is only processed once. > + > + Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and > + start it. After mScheduledQueue is drained check the > + mDiscoveredList to see if any item has a Depex that is ready to > + be placed on the mScheduledQueue. > + > + Step #3 - Adding to the mScheduledQueue requires that you process Before > + and After dependencies. This is done recursively as the call to add > + to the mScheduledQueue checks for Before and recursively adds > + all Befores. It then addes the item that was passed in and then > + processess the After dependecies by recursively calling the routine. > + > + Dispatcher Rules: > + The rules for the dispatcher are similar to the DXE dispatcher. > + > + The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3 > + is the state diagram for the DXE dispatcher > + > + Depex - Dependency Expresion. > + > + Copyright (c) 2014, Hewlett-Packard Development Company, L.P. > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +// > +// MM Dispatcher Data structures > +// > +#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w') > +typedef struct { > + UINTN Signature; > + LIST_ENTRY Link; // mFvHandleList > + EFI_HANDLE Handle; > +} KNOWN_HANDLE; > + > +// > +// Function Prototypes > +// > + > +EFI_STATUS > +MmCoreFfsFindMmDriver ( > + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader > + ); > + > +/** > + Insert InsertedDriverEntry onto the mScheduledQueue. To do this you > + must add any driver with a before dependency on InsertedDriverEntry first. > + You do this by recursively calling this routine. After all the Befores are > + processed you can add InsertedDriverEntry to the mScheduledQueue. > + Then you can add any driver with an After dependency on InsertedDriverEntry > + by recursively calling this routine. > + > + @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue > + > +**/ > +VOID > +MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( > + IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry > + ); > + > +// > +// The Driver List contains one copy of every driver that has been discovered. > +// Items are never removed from the driver list. List of EFI_MM_DRIVER_ENTRY > +// > +LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList); > + > +// > +// Queue of drivers that are ready to dispatch. This queue is a subset of the > +// mDiscoveredList.list of EFI_MM_DRIVER_ENTRY. > +// > +LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue); > + > +// > +// List of handles who's Fv's have been parsed and added to the mFwDriverList. > +// > +LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); > + > +// > +// Flag for the MM Dispacher. TRUE if dispatcher is execuing. > +// > +BOOLEAN gDispatcherRunning = FALSE; > + > +// > +// Flag for the MM Dispacher. TRUE if there is one or more MM drivers ready to be dispatched > +// > +BOOLEAN gRequestDispatch = FALSE; > + > +// > +// The global variable is defined for Loading modules at fixed address feature to track the MM code > +// memory range usage. It is a bit mapped array in which every bit indicates the correspoding > +// memory page available or not. > +// > +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mMmCodeMemoryRangeUsageBitMap=NULL; > + > +/** > + To check memory usage bit map array to figure out if the memory range in which the image will be loaded is available or not. If > + memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used. > + The function is only invoked when load modules at fixed address feature is enabled. > + > + @param ImageBase The base addres the image will be loaded at. > + @param ImageSize The size of the image > + > + @retval EFI_SUCCESS The memory range the image will be loaded in is available > + @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available > +**/ > +EFI_STATUS > +CheckAndMarkFixLoadingMemoryUsageBitMap ( > + IN EFI_PHYSICAL_ADDRESS ImageBase, > + IN UINTN ImageSize > + ) > +{ > + UINT32 MmCodePageNumber; > + UINT64 MmCodeSize; > + EFI_PHYSICAL_ADDRESS MmCodeBase; > + UINTN BaseOffsetPageNumber; > + UINTN TopOffsetPageNumber; > + UINTN Index; > + // > + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressMmCodePageNumber > + // > + MmCodePageNumber = 0; > + MmCodeSize = EFI_PAGES_TO_SIZE (MmCodePageNumber); > + MmCodeBase = gLoadModuleAtFixAddressMmramBase; > + > + // > + // If the memory usage bit map is not initialized, do it. Every bit in the array > + // indicate the status of the corresponding memory page, available or not > + // > + if (mMmCodeMemoryRangeUsageBitMap == NULL) { > + mMmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((MmCodePageNumber / 64) + 1)*sizeof(UINT64)); > + } > + // > + // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND > + // > + if (mMmCodeMemoryRangeUsageBitMap == NULL) { > + return EFI_NOT_FOUND; > + } > + // > + // see if the memory range for loading the image is in the MM code range. > + // > + if (MmCodeBase + MmCodeSize < ImageBase + ImageSize || MmCodeBase > ImageBase) { > + return EFI_NOT_FOUND; > + } > + // > + // Test if the memory is avalaible or not. > + // > + BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - MmCodeBase)); > + TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - MmCodeBase)); > + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) { > + if ((mMmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) { > + // > + // This page is already used. > + // > + return EFI_NOT_FOUND; > + } > + } > + > + // > + // Being here means the memory range is available. So mark the bits for the memory range > + // > + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) { > + mMmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64)); > + } > + return EFI_SUCCESS; > +} > +/** > + Get the fixed loading address from image header assigned by build tool. This function only be called > + when Loading module at Fixed address feature enabled. > + > + @param ImageContext Pointer to the image context structure that describes the PE/COFF > + image that needs to be examined by this function. > + @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . > + @retval EFI_NOT_FOUND The image has no assigned fixed loadding address. > + > +**/ > +EFI_STATUS > +GetPeCoffImageFixLoadingAssignedAddress( > + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext > + ) > +{ > + UINTN SectionHeaderOffset; > + EFI_STATUS Status; > + EFI_IMAGE_SECTION_HEADER SectionHeader; > + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; > + EFI_PHYSICAL_ADDRESS FixLoadingAddress; > + UINT16 Index; > + UINTN Size; > + UINT16 NumberOfSections; > + UINT64 ValueInSectionHeader; > + > + FixLoadingAddress = 0; > + Status = EFI_NOT_FOUND; > + > + // > + // Get PeHeader pointer > + // > + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset); > + SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + > + sizeof (UINT32) + > + sizeof (EFI_IMAGE_FILE_HEADER) + > + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; > + NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; > + > + // > + // Get base address from the first section header that doesn't point to code section. > + // > + for (Index = 0; Index < NumberOfSections; Index++) { > + // > + // Read section header from file > + // > + Size = sizeof (EFI_IMAGE_SECTION_HEADER); > + Status = ImageContext->ImageRead ( > + ImageContext->Handle, > + SectionHeaderOffset, > + &Size, > + &SectionHeader > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = EFI_NOT_FOUND; > + > + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { > + // > + // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header > + // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled, > + // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields > + // should not be Zero, or else, these 2 fields should be set to Zero > + // > + ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations); > + if (ValueInSectionHeader != 0) { > + // > + // Found first section header that doesn't point to code section in which build tool saves the > + // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields > + // > + FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressMmramBase + (INT64)ValueInSectionHeader); > + // > + // Check if the memory range is available. > + // > + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); > + if (!EFI_ERROR(Status)) { > + // > + // The assigned address is valid. Return the specified loading address > + // > + ImageContext->ImageAddress = FixLoadingAddress; > + } > + } > + break; > + } > + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); > + } > + DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status)); > + return Status; > +} > +/** > + Loads an EFI image into SMRAM. > + > + @param DriverEntry EFI_MM_DRIVER_ENTRY instance > + > + @return EFI_STATUS > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLoadImage ( > + IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry > + ) > +{ > + VOID *Buffer; > + UINTN PageCount; > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS DstBuffer; > + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; > + > + DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName)); > + > + Buffer = AllocateCopyPool (DriverEntry->Pe32DataSize, DriverEntry->Pe32Data); > + if (Buffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status = EFI_SUCCESS; > + > + // > + // Initialize ImageContext > + // > + ImageContext.Handle = Buffer; > + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; > + > + // > + // Get information about the image being loaded > + // > + Status = PeCoffLoaderGetImageInfo (&ImageContext); > + if (EFI_ERROR (Status)) { > + if (Buffer != NULL) { > + MmFreePool (Buffer); > + } > + return Status; > + } > + > + PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); > + DstBuffer = (UINTN)(-1); > + > + Status = MmAllocatePages ( > + AllocateMaxAddress, > + EfiRuntimeServicesCode, > + PageCount, > + &DstBuffer > + ); > + if (EFI_ERROR (Status)) { > + if (Buffer != NULL) { > + MmFreePool (Buffer); > + } > + return Status; > + } > + > + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; > + > + // > + // Align buffer on section boundry > + // > + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; > + ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); > + > + // > + // Load the image to our new buffer > + // > + Status = PeCoffLoaderLoadImage (&ImageContext); > + if (EFI_ERROR (Status)) { > + if (Buffer != NULL) { > + MmFreePool (Buffer); > + } > + MmFreePages (DstBuffer, PageCount); > + return Status; > + } > + > + // > + // Relocate the image in our new buffer > + // > + Status = PeCoffLoaderRelocateImage (&ImageContext); > + if (EFI_ERROR (Status)) { > + if (Buffer != NULL) { > + MmFreePool (Buffer); > + } > + MmFreePages (DstBuffer, PageCount); > + return Status; > + } > + > + // > + // Flush the instruction cache so the image data are written before we execute it > + // > + InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); > + > + // > + // Save Image EntryPoint in DriverEntry > + // > + DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; > + DriverEntry->ImageBuffer = DstBuffer; > + DriverEntry->NumberOfPage = PageCount; > + > + if (mEfiSystemTable != NULL) { > + Status = mEfiSystemTable->BootServices->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); > + if (EFI_ERROR (Status)) { > + if (Buffer != NULL) { > + MmFreePool (Buffer); > + } > + MmFreePages (DstBuffer, PageCount); > + return Status; > + } > + > + ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL)); > + // > + // Fill in the remaining fields of the Loaded Image Protocol instance. > + // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. > + // > + DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; > + DriverEntry->LoadedImage->ParentHandle = NULL; > + DriverEntry->LoadedImage->SystemTable = mEfiSystemTable; > + DriverEntry->LoadedImage->DeviceHandle = NULL; > + DriverEntry->LoadedImage->FilePath = NULL; > + > + DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; > + DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; > + DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; > + DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; > + > + // > + // Create a new image handle in the UEFI handle database for the MM Driver > + // > + DriverEntry->ImageHandle = NULL; > + Status = mEfiSystemTable->BootServices->InstallMultipleProtocolInterfaces ( > + &DriverEntry->ImageHandle, > + &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, > + NULL > + ); > + } > + > + // > + // Print the load address and the PDB file name if it is available > + // > + > + DEBUG_CODE_BEGIN (); > + > + UINTN Index; > + UINTN StartIndex; > + CHAR8 EfiFileName[256]; > + > + > + DEBUG ((DEBUG_INFO | DEBUG_LOAD, > + "Loading MM driver at 0x%11p EntryPoint=0x%11p ", > + (VOID *)(UINTN) ImageContext.ImageAddress, > + FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); > + > + > + // > + // Print Module Name by Pdb file path. > + // Windows and Unix style file path are all trimmed correctly. > + // > + if (ImageContext.PdbPointer != NULL) { > + StartIndex = 0; > + for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { > + if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { > + StartIndex = Index + 1; > + } > + } > + // > + // Copy the PDB file name to our temporary string, and replace .pdb with .efi > + // The PDB file name is limited in the range of 0~255. > + // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. > + // > + for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { > + EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; > + if (EfiFileName[Index] == 0) { > + EfiFileName[Index] = '.'; > + } > + if (EfiFileName[Index] == '.') { > + EfiFileName[Index + 1] = 'e'; > + EfiFileName[Index + 2] = 'f'; > + EfiFileName[Index + 3] = 'i'; > + EfiFileName[Index + 4] = 0; > + break; > + } > + } > + > + if (Index == sizeof (EfiFileName) - 4) { > + EfiFileName[Index] = 0; > + } > + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); > + } > + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); > + > + DEBUG_CODE_END (); > + > + // > + // Free buffer allocated by Fv->ReadSection. > + // > + // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection > + // used the UEFI Boot Services AllocatePool() function > + // > + MmFreePool(Buffer); > + return Status; > +} > + > +/** > + Preprocess dependency expression and update DriverEntry to reflect the > + state of Before and After dependencies. If DriverEntry->Before > + or DriverEntry->After is set it will never be cleared. > + > + @param DriverEntry DriverEntry element to update . > + > + @retval EFI_SUCCESS It always works. > + > +**/ > +EFI_STATUS > +MmPreProcessDepex ( > + IN EFI_MM_DRIVER_ENTRY *DriverEntry > + ) > +{ > + UINT8 *Iterator; > + > + Iterator = DriverEntry->Depex; > + DriverEntry->Dependent = TRUE; > + > + if (*Iterator == EFI_DEP_BEFORE) { > + DriverEntry->Before = TRUE; > + } else if (*Iterator == EFI_DEP_AFTER) { > + DriverEntry->After = TRUE; > + } > + > + if (DriverEntry->Before || DriverEntry->After) { > + CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID)); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Read Depex and pre-process the Depex for Before and After. If Section Extraction > + protocol returns an error via ReadSection defer the reading of the Depex. > + > + @param DriverEntry Driver to work on. > + > + @retval EFI_SUCCESS Depex read and preprossesed > + @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error > + and Depex reading needs to be retried. > + @retval Error DEPEX not found. > + > +**/ > +EFI_STATUS > +MmGetDepexSectionAndPreProccess ( > + IN EFI_MM_DRIVER_ENTRY *DriverEntry > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Data already read > + // > + if (DriverEntry->Depex == NULL) { > + Status = EFI_NOT_FOUND; > + } else { > + Status = EFI_SUCCESS; > + } > + if (EFI_ERROR (Status)) { > + if (Status == EFI_PROTOCOL_ERROR) { > + // > + // The section extraction protocol failed so set protocol error flag > + // > + DriverEntry->DepexProtocolError = TRUE; > + } else { > + // > + // If no Depex assume depend on all architectural protocols > + // > + DriverEntry->Depex = NULL; > + DriverEntry->Dependent = TRUE; > + DriverEntry->DepexProtocolError = FALSE; > + } > + } else { > + // > + // Set Before and After state information based on Depex > + // Driver will be put in Dependent state > + // > + MmPreProcessDepex (DriverEntry); > + DriverEntry->DepexProtocolError = FALSE; > + } > + > + return Status; > +} > + > +/** > + This is the main Dispatcher for MM and it exits when there are no more > + drivers to run. Drain the mScheduledQueue and load and start a PE > + image for each driver. Search the mDiscoveredList to see if any driver can > + be placed on the mScheduledQueue. If no drivers are placed on the > + mScheduledQueue exit the function. > + > + @retval EFI_SUCCESS All of the MM Drivers that could be dispatched > + have been run and the MM Entry Point has been > + registered. > + @retval EFI_NOT_READY The MM Driver that registered the MM Entry Point > + was just dispatched. > + @retval EFI_NOT_FOUND There are no MM Drivers available to be dispatched. > + @retval EFI_ALREADY_STARTED The MM Dispatcher is already running > + > +**/ > +EFI_STATUS > +MmDispatcher ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + LIST_ENTRY *Link; > + EFI_MM_DRIVER_ENTRY *DriverEntry; > + BOOLEAN ReadyToRun; > + BOOLEAN PreviousMmEntryPointRegistered; > + > + DEBUG ((DEBUG_INFO, "MmDispatcher\n")); > + > + if (!gRequestDispatch) { > + DEBUG ((DEBUG_INFO, " !gRequestDispatch\n")); > + return EFI_NOT_FOUND; > + } > + > + if (gDispatcherRunning) { > + DEBUG ((DEBUG_INFO, " gDispatcherRunning\n")); > + // > + // If the dispatcher is running don't let it be restarted. > + // > + return EFI_ALREADY_STARTED; > + } > + > + gDispatcherRunning = TRUE; > + > + do { > + // > + // Drain the Scheduled Queue > + // > + DEBUG ((DEBUG_INFO, " Drain the Scheduled Queue\n")); > + while (!IsListEmpty (&mScheduledQueue)) { > + DriverEntry = CR ( > + mScheduledQueue.ForwardLink, > + EFI_MM_DRIVER_ENTRY, > + ScheduledLink, > + EFI_MM_DRIVER_ENTRY_SIGNATURE > + ); > + DEBUG ((DEBUG_INFO, " DriverEntry (Scheduled) - %g\n", &DriverEntry->FileName)); > + > + // > + // Load the MM Driver image into memory. If the Driver was transitioned from > + // Untrused to Scheduled it would have already been loaded so we may need to > + // skip the LoadImage > + // > + if (DriverEntry->ImageHandle == NULL) { > + Status = MmLoadImage (DriverEntry); > + > + // > + // Update the driver state to reflect that it's been loaded > + // > + if (EFI_ERROR (Status)) { > + // > + // The MM Driver could not be loaded, and do not attempt to load or start it again. > + // Take driver from Scheduled to Initialized. > + // > + DriverEntry->Initialized = TRUE; > + DriverEntry->Scheduled = FALSE; > + RemoveEntryList (&DriverEntry->ScheduledLink); > + > + // > + // If it's an error don't try the StartImage > + // > + continue; > + } > + } > + > + DriverEntry->Scheduled = FALSE; > + DriverEntry->Initialized = TRUE; > + RemoveEntryList (&DriverEntry->ScheduledLink); > + > + /*REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( > + EFI_PROGRESS_CODE, > + EFI_SOFTWARE_MM_DRIVER | EFI_SW_PC_INIT_BEGIN, > + &DriverEntry->ImageHandle, > + sizeof (DriverEntry->ImageHandle) > + );*/ > + > + // > + // Cache state of MmEntryPointRegistered before calling entry point > + // > + PreviousMmEntryPointRegistered = gMmCorePrivate->MmEntryPointRegistered; > + > + // > + // For each MM driver, pass NULL as ImageHandle > + // > + if (mEfiSystemTable == NULL) { > + DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Standalone Mode)\n", DriverEntry->ImageEntryPoint)); > + Status = ((MM_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, &gMmCoreMmst); > + } else { > + DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Tradition Mode)\n", DriverEntry->ImageEntryPoint)); > + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, mEfiSystemTable); > + } > + if (EFI_ERROR(Status)){ > + DEBUG ((DEBUG_INFO, "StartImage Status - %r\n", Status)); > + MmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); > + } > + > + /*REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( > + EFI_PROGRESS_CODE, > + EFI_SOFTWARE_MM_DRIVER | EFI_SW_PC_INIT_END, > + &DriverEntry->ImageHandle, > + sizeof (DriverEntry->ImageHandle) > + );*/ > + > + if (!PreviousMmEntryPointRegistered && gMmCorePrivate->MmEntryPointRegistered) { > + // > + // Return immediately if the MM Entry Point was registered by the MM > + // Driver that was just dispatched. The MM IPL will reinvoke the MM > + // Core Dispatcher. This is required so MM Mode may be enabled as soon > + // as all the dependent MM Drivers for MM Mode have been dispatched. > + // Once the MM Entry Point has been registered, then MM Mode will be > + // used. > + // > + gRequestDispatch = TRUE; > + gDispatcherRunning = FALSE; > + return EFI_NOT_READY; > + } > + } > + > + // > + // Search DriverList for items to place on Scheduled Queue > + // > + DEBUG ((DEBUG_INFO, " Search DriverList for items to place on Scheduled Queue\n")); > + ReadyToRun = FALSE; > + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { > + DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); > + DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName)); > + > + if (DriverEntry->DepexProtocolError){ > + // > + // If Section Extraction Protocol did not let the Depex be read before retry the read > + // > + Status = MmGetDepexSectionAndPreProccess (DriverEntry); > + } > + > + if (DriverEntry->Dependent) { > + if (MmIsSchedulable (DriverEntry)) { > + MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); > + ReadyToRun = TRUE; > + } > + } > + } > + } while (ReadyToRun); > + > + // > + // If there is no more MM driver to dispatch, stop the dispatch request > + // > + DEBUG ((DEBUG_INFO, " no more MM driver to dispatch, stop the dispatch request\n")); > + gRequestDispatch = FALSE; > + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { > + DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); > + DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName)); > + > + if (!DriverEntry->Initialized){ > + // > + // We have MM driver pending to dispatch > + // > + gRequestDispatch = TRUE; > + break; > + } > + } > + > + gDispatcherRunning = FALSE; > + > + return EFI_SUCCESS; > +} > + > +/** > + Insert InsertedDriverEntry onto the mScheduledQueue. To do this you > + must add any driver with a before dependency on InsertedDriverEntry first. > + You do this by recursively calling this routine. After all the Befores are > + processed you can add InsertedDriverEntry to the mScheduledQueue. > + Then you can add any driver with an After dependency on InsertedDriverEntry > + by recursively calling this routine. > + > + @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue > + > +**/ > +VOID > +MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( > + IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry > + ) > +{ > + LIST_ENTRY *Link; > + EFI_MM_DRIVER_ENTRY *DriverEntry; > + > + // > + // Process Before Dependency > + // > + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { > + DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); > + if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) { > + DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); > + DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid)); > + if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { > + // > + // Recursively process BEFORE > + // > + DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n")); > + MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); > + } else { > + DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n")); > + } > + } > + } > + > + // > + // Convert driver from Dependent to Scheduled state > + // > + > + InsertedDriverEntry->Dependent = FALSE; > + InsertedDriverEntry->Scheduled = TRUE; > + InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink); > + > + > + // > + // Process After Dependency > + // > + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { > + DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); > + if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) { > + DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); > + DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid)); > + if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { > + // > + // Recursively process AFTER > + // > + DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n")); > + MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); > + } else { > + DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n")); > + } > + } > + } > +} > + > +/** > + Return TRUE if the Fv has been processed, FALSE if not. > + > + @param FvHandle The handle of a FV that's being tested > + > + @retval TRUE Fv protocol on FvHandle has been processed > + @retval FALSE Fv protocol on FvHandle has not yet been > + processed > + > +**/ > +BOOLEAN > +FvHasBeenProcessed ( > + IN EFI_HANDLE FvHandle > + ) > +{ > + LIST_ENTRY *Link; > + KNOWN_HANDLE *KnownHandle; > + > + for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) { > + KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE); > + if (KnownHandle->Handle == FvHandle) { > + return TRUE; > + } > + } > + return FALSE; > +} > + > +/** > + Remember that Fv protocol on FvHandle has had it's drivers placed on the > + mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are > + never removed/freed from the mFvHandleList. > + > + @param FvHandle The handle of a FV that has been processed > + > +**/ > +VOID > +FvIsBeingProcesssed ( > + IN EFI_HANDLE FvHandle > + ) > +{ > + KNOWN_HANDLE *KnownHandle; > + > + DEBUG ((DEBUG_INFO, "FvIsBeingProcesssed - 0x%08x\n", FvHandle)); > + > + KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE)); > + ASSERT (KnownHandle != NULL); > + > + KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; > + KnownHandle->Handle = FvHandle; > + InsertTailList (&mFvHandleList, &KnownHandle->Link); > +} > + > +/** > + Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry, > + and initilize any state variables. Read the Depex from the FV and store it > + in DriverEntry. Pre-process the Depex to set the Before and After state. > + The Discovered list is never free'ed and contains booleans that represent the > + other possible MM driver states. > + > + @param Fv Fv protocol, needed to read Depex info out of > + FLASH. > + @param FvHandle Handle for Fv, needed in the > + EFI_MM_DRIVER_ENTRY so that the PE image can be > + read out of the FV at a later time. > + @param DriverName Name of driver to add to mDiscoveredList. > + > + @retval EFI_SUCCESS If driver was added to the mDiscoveredList. > + @retval EFI_ALREADY_STARTED The driver has already been started. Only one > + DriverName may be active in the system at any one > + time. > + > +**/ > +EFI_STATUS > +MmAddToDriverList ( > + IN EFI_HANDLE FvHandle, > + IN VOID *Pe32Data, > + IN UINTN Pe32DataSize, > + IN VOID *Depex, > + IN UINTN DepexSize, > + IN EFI_GUID *DriverName > + ) > +{ > + EFI_MM_DRIVER_ENTRY *DriverEntry; > + > + DEBUG ((DEBUG_INFO, "MmAddToDriverList - %g (0x%08x)\n", DriverName, Pe32Data)); > + > + // > + // Create the Driver Entry for the list. ZeroPool initializes lots of variables to > + // NULL or FALSE. > + // > + DriverEntry = AllocateZeroPool (sizeof (EFI_MM_DRIVER_ENTRY)); > + ASSERT (DriverEntry != NULL); > + > + DriverEntry->Signature = EFI_MM_DRIVER_ENTRY_SIGNATURE; > + CopyGuid (&DriverEntry->FileName, DriverName); > + DriverEntry->FvHandle = FvHandle; > + DriverEntry->Pe32Data = Pe32Data; > + DriverEntry->Pe32DataSize = Pe32DataSize; > + DriverEntry->Depex = Depex; > + DriverEntry->DepexSize = DepexSize; > + > + MmGetDepexSectionAndPreProccess (DriverEntry); > + > + InsertTailList (&mDiscoveredList, &DriverEntry->Link); > + gRequestDispatch = TRUE; > + > + return EFI_SUCCESS; > +} > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + Event notification that is fired every time a FV dispatch protocol is added. > + More than one protocol may have been added when this event is fired, so you > + must loop on MmLocateHandle () to see how many protocols were added and > + do the following to each FV: > + If the Fv has already been processed, skip it. If the Fv has not been > + processed then mark it as being processed, as we are about to process it. > + Read the Fv and add any driver in the Fv to the mDiscoveredList.The > + mDiscoveredList is never free'ed and contains variables that define > + the other states the MM driver transitions to.. > + While you are at it read the A Priori file into memory. > + Place drivers in the A Priori list onto the mScheduledQueue. > + > + @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmDriverDispatchHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "MmDriverDispatchHandler\n")); > + > + // > + // Execute the MM Dispatcher on any newly discovered FVs and previously > + // discovered MM drivers that have been discovered but not dispatched. > + // > + Status = MmDispatcher (); > + > + // > + // Check to see if CommBuffer and CommBufferSize are valid > + // > + if (CommBuffer != NULL && CommBufferSize != NULL) { > + if (*CommBufferSize > 0) { > + if (Status == EFI_NOT_READY) { > + // > + // If a the MM Core Entry Point was just registered, then set flag to > + // request the MM Dispatcher to be restarted. > + // > + *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_RESTART; > + } else if (!EFI_ERROR (Status)) { > + // > + // Set the flag to show that the MM Dispatcher executed without errors > + // > + *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_SUCCESS; > + } else { > + // > + // Set the flag to show that the MM Dispatcher encountered an error > + // > + *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_ERROR; > + } > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFvDispatchHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_FV_DISPATCH_DATA *CommunicationFvDispatchData; > + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; > + > + DEBUG ((DEBUG_INFO, "MmFvDispatchHandler\n")); > + > + CommunicationFvDispatchData = CommBuffer; > + > + DEBUG ((DEBUG_INFO, " Dispatch - 0x%016lx - 0x%016lx\n", CommunicationFvDispatchData->Address, CommunicationFvDispatchData->Size)); > + > + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)CommunicationFvDispatchData->Address; > + > + MmCoreFfsFindMmDriver (FwVolHeader); > + > + // > + // Execute the MM Dispatcher on any newly discovered FVs and previously > + // discovered MM drivers that have been discovered but not dispatched. > + // > + Status = MmDispatcher (); > + > + return Status; > +} > + > +/** > + Traverse the discovered list for any drivers that were discovered but not loaded > + because the dependency experessions evaluated to false. > + > +**/ > +VOID > +MmDisplayDiscoveredNotDispatched ( > + VOID > + ) > +{ > + LIST_ENTRY *Link; > + EFI_MM_DRIVER_ENTRY *DriverEntry; > + > + for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) { > + DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE); > + if (DriverEntry->Dependent) { > + DEBUG ((DEBUG_LOAD, "MM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); > + } > + } > +} > diff --git a/StandaloneMmPkg/Core/FwVol.c b/StandaloneMmPkg/Core/FwVol.c > new file mode 100644 > index 0000000000..901c58bc53 > --- /dev/null > +++ b/StandaloneMmPkg/Core/FwVol.c > @@ -0,0 +1,104 @@ > +/**@file > + > +Copyright (c) 2015, Intel Corporation. All rights reserved.
> +Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD License > +which accompanies this distribution. The full text of the license may be found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > +#include > + > +// > +// List of file types supported by dispatcher > +// > +EFI_FV_FILETYPE mMmFileTypes[] = { > + EFI_FV_FILETYPE_MM, > + 0xE, //EFI_FV_FILETYPE_MM_STANDALONE, > + // > + // Note: DXE core will process the FV image file, so skip it in MM core > + // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE > + // > +}; > + > +EFI_STATUS > +MmAddToDriverList ( > + IN EFI_HANDLE FvHandle, > + IN VOID *Pe32Data, > + IN UINTN Pe32DataSize, > + IN VOID *Depex, > + IN UINTN DepexSize, > + IN EFI_GUID *DriverName > + ); > + > +BOOLEAN > +FvHasBeenProcessed ( > + IN EFI_HANDLE FvHandle > + ); > + > +VOID > +FvIsBeingProcesssed ( > + IN EFI_HANDLE FvHandle > + ); > + > +EFI_STATUS > +MmCoreFfsFindMmDriver ( > + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader > + ) > +/*++ > + > +Routine Description: > + Given the pointer to the Firmware Volume Header find the > + MM driver and return it's PE32 image. > + > +Arguments: > + FwVolHeader - Pointer to memory mapped FV > + > +Returns: > + other - Failure > + > +--*/ > +{ > + EFI_STATUS Status; > + EFI_STATUS DepexStatus; > + EFI_FFS_FILE_HEADER *FileHeader; > + EFI_FV_FILETYPE FileType; > + VOID *Pe32Data; > + UINTN Pe32DataSize; > + VOID *Depex; > + UINTN DepexSize; > + UINTN Index; > + > + DEBUG((DEBUG_INFO, "MmCoreFfsFindMmDriver - 0x%x\n", FwVolHeader)); > + > + if (FvHasBeenProcessed (FwVolHeader)) { > + return EFI_SUCCESS; > + } > + > + FvIsBeingProcesssed (FwVolHeader); > + > + for (Index = 0; Index < sizeof(mMmFileTypes) / sizeof(mMmFileTypes[0]); Index++) { > + DEBUG((DEBUG_INFO, "Check MmFileTypes - 0x%x\n", mMmFileTypes[Index])); > + FileType = mMmFileTypes[Index]; > + FileHeader = NULL; > + do { > + Status = FfsFindNextFile(FileType, FwVolHeader, &FileHeader); > + if (!EFI_ERROR(Status)) { > + Status = FfsFindSectionData(EFI_SECTION_PE32, FileHeader, &Pe32Data, &Pe32DataSize); > + DEBUG((DEBUG_INFO, "Find PE data - 0x%x\n", Pe32Data)); > + DepexStatus = FfsFindSectionData(EFI_SECTION_MM_DEPEX, FileHeader, &Depex, &DepexSize); > + if (!EFI_ERROR(DepexStatus)) { > + MmAddToDriverList(FwVolHeader, Pe32Data, Pe32DataSize, Depex, DepexSize, &FileHeader->Name); > + } > + } > + } while (!EFI_ERROR(Status)); > + } > + > + return Status; > +} > diff --git a/StandaloneMmPkg/Core/Handle.c b/StandaloneMmPkg/Core/Handle.c > new file mode 100644 > index 0000000000..01832f4bbe > --- /dev/null > +++ b/StandaloneMmPkg/Core/Handle.c > @@ -0,0 +1,533 @@ > +/** @file > + SMM handle & protocol handling. > + > + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +// > +// mProtocolDatabase - A list of all protocols in the system. (simple list for now) > +// gHandleList - A list of all the handles in the system > +// > +LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase); > +LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList); > + > +/** > + Check whether a handle is a valid EFI_HANDLE > + > + @param UserHandle The handle to check > + > + @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE. > + @retval EFI_SUCCESS The handle is valid EFI_HANDLE. > + > +**/ > +EFI_STATUS > +MmValidateHandle ( > + IN EFI_HANDLE UserHandle > + ) > +{ > + IHANDLE *Handle; > + > + Handle = (IHANDLE *)UserHandle; > + if (Handle == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + if (Handle->Signature != EFI_HANDLE_SIGNATURE) { > + return EFI_INVALID_PARAMETER; > + } > + return EFI_SUCCESS; > +} > + > +/** > + Finds the protocol entry for the requested protocol. > + > + @param Protocol The ID of the protocol > + @param Create Create a new entry if not found > + > + @return Protocol entry > + > +**/ > +PROTOCOL_ENTRY * > +MmFindProtocolEntry ( > + IN EFI_GUID *Protocol, > + IN BOOLEAN Create > + ) > +{ > + LIST_ENTRY *Link; > + PROTOCOL_ENTRY *Item; > + PROTOCOL_ENTRY *ProtEntry; > + > + // > + // Search the database for the matching GUID > + // > + > + ProtEntry = NULL; > + for (Link = mProtocolDatabase.ForwardLink; > + Link != &mProtocolDatabase; > + Link = Link->ForwardLink) { > + > + Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE); > + if (CompareGuid (&Item->ProtocolID, Protocol)) { > + // > + // This is the protocol entry > + // > + ProtEntry = Item; > + break; > + } > + } > + > + // > + // If the protocol entry was not found and Create is TRUE, then > + // allocate a new entry > + // > + if ((ProtEntry == NULL) && Create) { > + ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY)); > + if (ProtEntry != NULL) { > + // > + // Initialize new protocol entry structure > + // > + ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE; > + CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol); > + InitializeListHead (&ProtEntry->Protocols); > + InitializeListHead (&ProtEntry->Notify); > + > + // > + // Add it to protocol database > + // > + InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); > + } > + } > + return ProtEntry; > +} > + > +/** > + Finds the protocol instance for the requested handle and protocol. > + Note: This function doesn't do parameters checking, it's caller's responsibility > + to pass in valid parameters. > + > + @param Handle The handle to search the protocol on > + @param Protocol GUID of the protocol > + @param Interface The interface for the protocol being searched > + > + @return Protocol instance (NULL: Not found) > + > +**/ > +PROTOCOL_INTERFACE * > +MmFindProtocolInterface ( > + IN IHANDLE *Handle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ) > +{ > + PROTOCOL_INTERFACE *Prot; > + PROTOCOL_ENTRY *ProtEntry; > + LIST_ENTRY *Link; > + > + Prot = NULL; > + > + // > + // Lookup the protocol entry for this protocol ID > + // > + ProtEntry = MmFindProtocolEntry (Protocol, FALSE); > + if (ProtEntry != NULL) { > + // > + // Look at each protocol interface for any matches > + // > + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) { > + // > + // If this protocol interface matches, remove it > + // > + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); > + if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) { > + break; > + } > + Prot = NULL; > + } > + } > + return Prot; > +} > + > +/** > + Wrapper function to MmInstallProtocolInterfaceNotify. This is the public API which > + Calls the private one which contains a BOOLEAN parameter for notifications > + > + @param UserHandle The handle to install the protocol handler on, > + or NULL if a new handle is to be allocated > + @param Protocol The protocol to add to the handle > + @param InterfaceType Indicates whether Interface is supplied in > + native form. > + @param Interface The interface for the protocol being added > + > + @return Status code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInstallProtocolInterface ( > + IN OUT EFI_HANDLE *UserHandle, > + IN EFI_GUID *Protocol, > + IN EFI_INTERFACE_TYPE InterfaceType, > + IN VOID *Interface > + ) > +{ > + return MmInstallProtocolInterfaceNotify ( > + UserHandle, > + Protocol, > + InterfaceType, > + Interface, > + TRUE > + ); > +} > + > +/** > + Installs a protocol interface into the boot services environment. > + > + @param UserHandle The handle to install the protocol handler on, > + or NULL if a new handle is to be allocated > + @param Protocol The protocol to add to the handle > + @param InterfaceType Indicates whether Interface is supplied in > + native form. > + @param Interface The interface for the protocol being added > + @param Notify indicates whether notify the notification list > + for this protocol > + > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate > + @retval EFI_SUCCESS Protocol interface successfully installed > + > +**/ > +EFI_STATUS > +MmInstallProtocolInterfaceNotify ( > + IN OUT EFI_HANDLE *UserHandle, > + IN EFI_GUID *Protocol, > + IN EFI_INTERFACE_TYPE InterfaceType, > + IN VOID *Interface, > + IN BOOLEAN Notify > + ) > +{ > + PROTOCOL_INTERFACE *Prot; > + PROTOCOL_ENTRY *ProtEntry; > + IHANDLE *Handle; > + EFI_STATUS Status; > + VOID *ExistingInterface; > + > + // > + // returns EFI_INVALID_PARAMETER if InterfaceType is invalid. > + // Also added check for invalid UserHandle and Protocol pointers. > + // > + if (UserHandle == NULL || Protocol == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (InterfaceType != EFI_NATIVE_INTERFACE) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Print debug message > + // > + DEBUG((DEBUG_LOAD | DEBUG_INFO, "MmInstallProtocolInterface: %g %p\n", Protocol, Interface)); > + > + Status = EFI_OUT_OF_RESOURCES; > + Prot = NULL; > + Handle = NULL; > + > + if (*UserHandle != NULL) { > + Status = MmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface); > + if (!EFI_ERROR (Status)) { > + return EFI_INVALID_PARAMETER; > + } > + } > + > + // > + // Lookup the Protocol Entry for the requested protocol > + // > + ProtEntry = MmFindProtocolEntry (Protocol, TRUE); > + if (ProtEntry == NULL) { > + goto Done; > + } > + > + // > + // Allocate a new protocol interface structure > + // > + Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE)); > + if (Prot == NULL) { > + Status = EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + // > + // If caller didn't supply a handle, allocate a new one > + // > + Handle = (IHANDLE *)*UserHandle; > + if (Handle == NULL) { > + Handle = AllocateZeroPool (sizeof(IHANDLE)); > + if (Handle == NULL) { > + Status = EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + // > + // Initialize new handler structure > + // > + Handle->Signature = EFI_HANDLE_SIGNATURE; > + InitializeListHead (&Handle->Protocols); > + > + // > + // Add this handle to the list global list of all handles > + // in the system > + // > + InsertTailList (&gHandleList, &Handle->AllHandles); > + } > + > + Status = MmValidateHandle (Handle); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Each interface that is added must be unique > + // > + ASSERT (MmFindProtocolInterface (Handle, Protocol, Interface) == NULL); > + > + // > + // Initialize the protocol interface structure > + // > + Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE; > + Prot->Handle = Handle; > + Prot->Protocol = ProtEntry; > + Prot->Interface = Interface; > + > + // > + // Add this protocol interface to the head of the supported > + // protocol list for this handle > + // > + InsertHeadList (&Handle->Protocols, &Prot->Link); > + > + // > + // Add this protocol interface to the tail of the > + // protocol entry > + // > + InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); > + > + // > + // Notify the notification list for this protocol > + // > + if (Notify) { > + MmNotifyProtocol (Prot); > + } > + Status = EFI_SUCCESS; > + > +Done: > + if (!EFI_ERROR (Status)) { > + // > + // Return the new handle back to the caller > + // > + *UserHandle = Handle; > + } else { > + // > + // There was an error, clean up > + // > + if (Prot != NULL) { > + FreePool (Prot); > + } > + } > + return Status; > +} > + > +/** > + Uninstalls all instances of a protocol:interfacer from a handle. > + If the last protocol interface is remove from the handle, the > + handle is freed. > + > + @param UserHandle The handle to remove the protocol handler from > + @param Protocol The protocol, of protocol:interface, to remove > + @param Interface The interface, of protocol:interface, to remove > + > + @retval EFI_INVALID_PARAMETER Protocol is NULL. > + @retval EFI_SUCCESS Protocol interface successfully uninstalled. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmUninstallProtocolInterface ( > + IN EFI_HANDLE UserHandle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ) > +{ > + EFI_STATUS Status; > + IHANDLE *Handle; > + PROTOCOL_INTERFACE *Prot; > + > + // > + // Check that Protocol is valid > + // > + if (Protocol == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check that UserHandle is a valid handle > + // > + Status = MmValidateHandle (UserHandle); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Check that Protocol exists on UserHandle, and Interface matches the interface in the database > + // > + Prot = MmFindProtocolInterface (UserHandle, Protocol, Interface); > + if (Prot == NULL) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Remove the protocol interface from the protocol > + // > + Status = EFI_NOT_FOUND; > + Handle = (IHANDLE *)UserHandle; > + Prot = MmRemoveInterfaceFromProtocol (Handle, Protocol, Interface); > + > + if (Prot != NULL) { > + // > + // Remove the protocol interface from the handle > + // > + RemoveEntryList (&Prot->Link); > + > + // > + // Free the memory > + // > + Prot->Signature = 0; > + FreePool (Prot); > + Status = EFI_SUCCESS; > + } > + > + // > + // If there are no more handlers for the handle, free the handle > + // > + if (IsListEmpty (&Handle->Protocols)) { > + Handle->Signature = 0; > + RemoveEntryList (&Handle->AllHandles); > + FreePool (Handle); > + } > + return Status; > +} > + > +/** > + Locate a certain GUID protocol interface in a Handle's protocols. > + > + @param UserHandle The handle to obtain the protocol interface on > + @param Protocol The GUID of the protocol > + > + @return The requested protocol interface for the handle > + > +**/ > +PROTOCOL_INTERFACE * > +MmGetProtocolInterface ( > + IN EFI_HANDLE UserHandle, > + IN EFI_GUID *Protocol > + ) > +{ > + EFI_STATUS Status; > + PROTOCOL_ENTRY *ProtEntry; > + PROTOCOL_INTERFACE *Prot; > + IHANDLE *Handle; > + LIST_ENTRY *Link; > + > + Status = MmValidateHandle (UserHandle); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + > + Handle = (IHANDLE *)UserHandle; > + > + // > + // Look at each protocol interface for a match > + // > + for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { > + Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); > + ProtEntry = Prot->Protocol; > + if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) { > + return Prot; > + } > + } > + return NULL; > +} > + > +/** > + Queries a handle to determine if it supports a specified protocol. > + > + @param UserHandle The handle being queried. > + @param Protocol The published unique identifier of the protocol. > + @param Interface Supplies the address where a pointer to the > + corresponding Protocol Interface is returned. > + > + @retval EFI_SUCCESS The interface information for the specified protocol was returned. > + @retval EFI_UNSUPPORTED The device does not support the specified protocol. > + @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.. > + @retval EFI_INVALID_PARAMETER Protocol is NULL. > + @retval EFI_INVALID_PARAMETER Interface is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmHandleProtocol ( > + IN EFI_HANDLE UserHandle, > + IN EFI_GUID *Protocol, > + OUT VOID **Interface > + ) > +{ > + EFI_STATUS Status; > + PROTOCOL_INTERFACE *Prot; > + > + // > + // Check for invalid Protocol > + // > + if (Protocol == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check for invalid Interface > + // > + if (Interface == NULL) { > + return EFI_INVALID_PARAMETER; > + } else { > + *Interface = NULL; > + } > + > + // > + // Check for invalid UserHandle > + // > + Status = MmValidateHandle (UserHandle); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Look at each protocol interface for a match > + // > + Prot = MmGetProtocolInterface (UserHandle, Protocol); > + if (Prot == NULL) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // This is the protocol interface entry for this protocol > + // > + *Interface = Prot->Interface; > + > + return EFI_SUCCESS; > +} > diff --git a/StandaloneMmPkg/Core/InstallConfigurationTable.c b/StandaloneMmPkg/Core/InstallConfigurationTable.c > new file mode 100644 > index 0000000000..3a31c63f94 > --- /dev/null > +++ b/StandaloneMmPkg/Core/InstallConfigurationTable.c > @@ -0,0 +1,178 @@ > +/** @file > + System Management System Table Services MmInstallConfigurationTable service > + > + Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +#define CONFIG_TABLE_SIZE_INCREASED 0x10 > + > +UINTN mMmSystemTableAllocateSize = 0; > + > +/** > + The MmInstallConfigurationTable() function is used to maintain the list > + of configuration tables that are stored in the System Management System > + Table. The list is stored as an array of (GUID, Pointer) pairs. The list > + must be allocated from pool memory with PoolType set to EfiRuntimeServicesData. > + > + @param SystemTable A pointer to the SMM System Table (SMST). > + @param Guid A pointer to the GUID for the entry to add, update, or remove. > + @param Table A pointer to the buffer of the table to add. > + @param TableSize The size of the table to install. > + > + @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed. > + @retval EFI_INVALID_PARAMETER Guid is not valid. > + @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInstallConfigurationTable ( > + IN CONST EFI_MM_SYSTEM_TABLE *SystemTable, > + IN CONST EFI_GUID *Guid, > + IN VOID *Table, > + IN UINTN TableSize > + ) > +{ > + UINTN Index; > + EFI_CONFIGURATION_TABLE *ConfigurationTable; > + EFI_CONFIGURATION_TABLE *OldTable; > + > + // > + // If Guid is NULL, then this operation cannot be performed > + // > + if (Guid == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + ConfigurationTable = gMmCoreMmst.MmConfigurationTable; > + > + // > + // Search all the table for an entry that matches Guid > + // > + for (Index = 0; Index < gMmCoreMmst.NumberOfTableEntries; Index++) { > + if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) { > + break; > + } > + } > + > + if (Index < gMmCoreMmst.NumberOfTableEntries) { > + // > + // A match was found, so this is either a modify or a delete operation > + // > + if (Table != NULL) { > + // > + // If Table is not NULL, then this is a modify operation. > + // Modify the table entry and return. > + // > + ConfigurationTable[Index].VendorTable = Table; > + return EFI_SUCCESS; > + } > + > + // > + // A match was found and Table is NULL, so this is a delete operation. > + // > + gMmCoreMmst.NumberOfTableEntries--; > + > + // > + // Copy over deleted entry > + // > + CopyMem ( > + &(ConfigurationTable[Index]), > + &(ConfigurationTable[Index + 1]), > + (gMmCoreMmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE) > + ); > + > + } else { > + // > + // No matching GUIDs were found, so this is an add operation. > + // > + if (Table == NULL) { > + // > + // If Table is NULL on an add operation, then return an error. > + // > + return EFI_NOT_FOUND; > + } > + > + // > + // Assume that Index == gMmCoreMmst.NumberOfTableEntries > + // > + if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mMmSystemTableAllocateSize) { > + // > + // Allocate a table with one additional entry. > + // > + mMmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE)); > + ConfigurationTable = AllocatePool (mMmSystemTableAllocateSize); > + if (ConfigurationTable == NULL) { > + // > + // If a new table could not be allocated, then return an error. > + // > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (gMmCoreMmst.MmConfigurationTable != NULL) { > + // > + // Copy the old table to the new table. > + // > + CopyMem ( > + ConfigurationTable, > + gMmCoreMmst.MmConfigurationTable, > + Index * sizeof (EFI_CONFIGURATION_TABLE) > + ); > + > + // > + // Record the old table pointer. > + // > + OldTable = gMmCoreMmst.MmConfigurationTable; > + > + // > + // As the MmInstallConfigurationTable() may be re-entered by FreePool() in > + // its calling stack, updating System table to the new table pointer must > + // be done before calling FreePool() to free the old table. > + // It can make sure the gMmCoreMmst.MmConfigurationTable point to the new > + // table and avoid the errors of use-after-free to the old table by the > + // reenter of MmInstallConfigurationTable() in FreePool()'s calling stack. > + // > + gMmCoreMmst.MmConfigurationTable = ConfigurationTable; > + > + // > + // Free the old table after updating System Table to the new table pointer. > + // > + FreePool (OldTable); > + } else { > + // > + // Update System Table > + // > + gMmCoreMmst.MmConfigurationTable = ConfigurationTable; > + } > + } > + > + // > + // Fill in the new entry > + // > + CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid); > + ConfigurationTable[Index].VendorTable = Table; > + > + // > + // This is an add operation, so increment the number of table entries > + // > + gMmCoreMmst.NumberOfTableEntries++; > + } > + > + // > + // CRC-32 field is ignorable for SMM System Table and should be set to zero > + // > + > + return EFI_SUCCESS; > +} > diff --git a/StandaloneMmPkg/Core/Locate.c b/StandaloneMmPkg/Core/Locate.c > new file mode 100644 > index 0000000000..6a90575f99 > --- /dev/null > +++ b/StandaloneMmPkg/Core/Locate.c > @@ -0,0 +1,496 @@ > +/** @file > + Locate handle functions > + > + Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +// > +// ProtocolRequest - Last LocateHandle request ID > +// > +UINTN mEfiLocateHandleRequest = 0; > + > +// > +// Internal prototypes > +// > + > +typedef struct { > + EFI_GUID *Protocol; > + VOID *SearchKey; > + LIST_ENTRY *Position; > + PROTOCOL_ENTRY *ProtEntry; > +} LOCATE_POSITION; > + > +typedef > +IHANDLE * > +(* CORE_GET_NEXT) ( > + IN OUT LOCATE_POSITION *Position, > + OUT VOID **Interface > + ); > + > +/** > + Routine to get the next Handle, when you are searching for all handles. > + > + @param Position Information about which Handle to seach for. > + @param Interface Return the interface structure for the matching > + protocol. > + > + @return An pointer to IHANDLE if the next Position is not the end of the list. > + Otherwise,NULL is returned. > + > +**/ > +IHANDLE * > +MmGetNextLocateAllHandles ( > + IN OUT LOCATE_POSITION *Position, > + OUT VOID **Interface > + ) > +{ > + IHANDLE *Handle; > + > + // > + // Next handle > + // > + Position->Position = Position->Position->ForwardLink; > + > + // > + // If not at the end of the list, get the handle > + // > + Handle = NULL; > + *Interface = NULL; > + if (Position->Position != &gHandleList) { > + Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); > + } > + return Handle; > +} > + > +/** > + Routine to get the next Handle, when you are searching for register protocol > + notifies. > + > + @param Position Information about which Handle to seach for. > + @param Interface Return the interface structure for the matching > + protocol. > + > + @return An pointer to IHANDLE if the next Position is not the end of the list. > + Otherwise,NULL is returned. > + > +**/ > +IHANDLE * > +MmGetNextLocateByRegisterNotify ( > + IN OUT LOCATE_POSITION *Position, > + OUT VOID **Interface > + ) > +{ > + IHANDLE *Handle; > + PROTOCOL_NOTIFY *ProtNotify; > + PROTOCOL_INTERFACE *Prot; > + LIST_ENTRY *Link; > + > + Handle = NULL; > + *Interface = NULL; > + ProtNotify = Position->SearchKey; > + > + // > + // If this is the first request, get the next handle > + // > + if (ProtNotify != NULL) { > + ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE); > + Position->SearchKey = NULL; > + > + // > + // If not at the end of the list, get the next handle > + // > + Link = ProtNotify->Position->ForwardLink; > + if (Link != &ProtNotify->Protocol->Protocols) { > + Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); > + Handle = Prot->Handle; > + *Interface = Prot->Interface; > + } > + } > + return Handle; > +} > + > +/** > + Routine to get the next Handle, when you are searching for a given protocol. > + > + @param Position Information about which Handle to seach for. > + @param Interface Return the interface structure for the matching > + protocol. > + > + @return An pointer to IHANDLE if the next Position is not the end of the list. > + Otherwise,NULL is returned. > + > +**/ > +IHANDLE * > +MmGetNextLocateByProtocol ( > + IN OUT LOCATE_POSITION *Position, > + OUT VOID **Interface > + ) > +{ > + IHANDLE *Handle; > + LIST_ENTRY *Link; > + PROTOCOL_INTERFACE *Prot; > + > + Handle = NULL; > + *Interface = NULL; > + for (; ;) { > + // > + // Next entry > + // > + Link = Position->Position->ForwardLink; > + Position->Position = Link; > + > + // > + // If not at the end, return the handle > + // > + if (Link == &Position->ProtEntry->Protocols) { > + Handle = NULL; > + break; > + } > + > + // > + // Get the handle > + // > + Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); > + Handle = Prot->Handle; > + *Interface = Prot->Interface; > + > + // > + // If this handle has not been returned this request, then > + // return it now > + // > + if (Handle->LocateRequest != mEfiLocateHandleRequest) { > + Handle->LocateRequest = mEfiLocateHandleRequest; > + break; > + } > + } > + return Handle; > +} > + > +/** > + Return the first Protocol Interface that matches the Protocol GUID. If > + Registration is pasased in return a Protocol Instance that was just add > + to the system. If Retistration is NULL return the first Protocol Interface > + you find. > + > + @param Protocol The protocol to search for > + @param Registration Optional Registration Key returned from > + RegisterProtocolNotify() > + @param Interface Return the Protocol interface (instance). > + > + @retval EFI_SUCCESS If a valid Interface is returned > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_NOT_FOUND Protocol interface not found > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLocateProtocol ( > + IN EFI_GUID *Protocol, > + IN VOID *Registration OPTIONAL, > + OUT VOID **Interface > + ) > +{ > + EFI_STATUS Status; > + LOCATE_POSITION Position; > + PROTOCOL_NOTIFY *ProtNotify; > + IHANDLE *Handle; > + > + if ((Interface == NULL) || (Protocol == NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + *Interface = NULL; > + Status = EFI_SUCCESS; > + > + // > + // Set initial position > + // > + Position.Protocol = Protocol; > + Position.SearchKey = Registration; > + Position.Position = &gHandleList; > + > + mEfiLocateHandleRequest += 1; > + > + if (Registration == NULL) { > + // > + // Look up the protocol entry and set the head pointer > + // > + Position.ProtEntry = MmFindProtocolEntry (Protocol, FALSE); > + if (Position.ProtEntry == NULL) { > + return EFI_NOT_FOUND; > + } > + Position.Position = &Position.ProtEntry->Protocols; > + > + Handle = MmGetNextLocateByProtocol (&Position, Interface); > + } else { > + Handle = MmGetNextLocateByRegisterNotify (&Position, Interface); > + } > + > + if (Handle == NULL) { > + Status = EFI_NOT_FOUND; > + } else if (Registration != NULL) { > + // > + // If this is a search by register notify and a handle was > + // returned, update the register notification position > + // > + ProtNotify = Registration; > + ProtNotify->Position = ProtNotify->Position->ForwardLink; > + } > + > + return Status; > +} > + > +/** > + Locates the requested handle(s) and returns them in Buffer. > + > + @param SearchType The type of search to perform to locate the > + handles > + @param Protocol The protocol to search for > + @param SearchKey Dependant on SearchType > + @param BufferSize On input the size of Buffer. On output the > + size of data returned. > + @param Buffer The buffer to return the results in > + > + @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is > + returned in BufferSize. > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_SUCCESS Successfully found the requested handle(s) and > + returns them in Buffer. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLocateHandle ( > + IN EFI_LOCATE_SEARCH_TYPE SearchType, > + IN EFI_GUID *Protocol OPTIONAL, > + IN VOID *SearchKey OPTIONAL, > + IN OUT UINTN *BufferSize, > + OUT EFI_HANDLE *Buffer > + ) > +{ > + EFI_STATUS Status; > + LOCATE_POSITION Position; > + PROTOCOL_NOTIFY *ProtNotify; > + CORE_GET_NEXT GetNext; > + UINTN ResultSize; > + IHANDLE *Handle; > + IHANDLE **ResultBuffer; > + VOID *Interface; > + > + if (BufferSize == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((*BufferSize > 0) && (Buffer == NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + GetNext = NULL; > + > + // > + // Set initial position > + // > + Position.Protocol = Protocol; > + Position.SearchKey = SearchKey; > + Position.Position = &gHandleList; > + > + ResultSize = 0; > + ResultBuffer = (IHANDLE **) Buffer; > + Status = EFI_SUCCESS; > + > + // > + // Get the search function based on type > + // > + switch (SearchType) { > + case AllHandles: > + GetNext = MmGetNextLocateAllHandles; > + break; > + > + case ByRegisterNotify: > + GetNext = MmGetNextLocateByRegisterNotify; > + // > + // Must have SearchKey for locate ByRegisterNotify > + // > + if (SearchKey == NULL) { > + Status = EFI_INVALID_PARAMETER; > + } > + break; > + > + case ByProtocol: > + GetNext = MmGetNextLocateByProtocol; > + if (Protocol == NULL) { > + Status = EFI_INVALID_PARAMETER; > + break; > + } > + // > + // Look up the protocol entry and set the head pointer > + // > + Position.ProtEntry = MmFindProtocolEntry (Protocol, FALSE); > + if (Position.ProtEntry == NULL) { > + Status = EFI_NOT_FOUND; > + break; > + } > + Position.Position = &Position.ProtEntry->Protocols; > + break; > + > + default: > + Status = EFI_INVALID_PARAMETER; > + break; > + } > + > + if (EFI_ERROR(Status)) { > + return Status; > + } > + > + // > + // Enumerate out the matching handles > + // > + mEfiLocateHandleRequest += 1; > + for (; ;) { > + // > + // Get the next handle. If no more handles, stop > + // > + Handle = GetNext (&Position, &Interface); > + if (NULL == Handle) { > + break; > + } > + > + // > + // Increase the resulting buffer size, and if this handle > + // fits return it > + // > + ResultSize += sizeof(Handle); > + if (ResultSize <= *BufferSize) { > + *ResultBuffer = Handle; > + ResultBuffer += 1; > + } > + } > + > + // > + // If the result is a zero length buffer, then there were no > + // matching handles > + // > + if (ResultSize == 0) { > + Status = EFI_NOT_FOUND; > + } else { > + // > + // Return the resulting buffer size. If it's larger than what > + // was passed, then set the error code > + // > + if (ResultSize > *BufferSize) { > + Status = EFI_BUFFER_TOO_SMALL; > + } > + > + *BufferSize = ResultSize; > + > + if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) { > + ASSERT (SearchKey != NULL); > + // > + // If this is a search by register notify and a handle was > + // returned, update the register notification position > + // > + ProtNotify = SearchKey; > + ProtNotify->Position = ProtNotify->Position->ForwardLink; > + } > + } > + > + return Status; > +} > + > +/** > + Function returns an array of handles that support the requested protocol > + in a buffer allocated from pool. This is a version of MmLocateHandle() > + that allocates a buffer for the caller. > + > + @param SearchType Specifies which handle(s) are to be returned. > + @param Protocol Provides the protocol to search by. This > + parameter is only valid for SearchType > + ByProtocol. > + @param SearchKey Supplies the search key depending on the > + SearchType. > + @param NumberHandles The number of handles returned in Buffer. > + @param Buffer A pointer to the buffer to return the requested > + array of handles that support Protocol. > + > + @retval EFI_SUCCESS The result array of handles was returned. > + @retval EFI_NOT_FOUND No handles match the search. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the > + matching results. > + @retval EFI_INVALID_PARAMETER One or more parameters are not valid. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLocateHandleBuffer ( > + IN EFI_LOCATE_SEARCH_TYPE SearchType, > + IN EFI_GUID *Protocol OPTIONAL, > + IN VOID *SearchKey OPTIONAL, > + IN OUT UINTN *NumberHandles, > + OUT EFI_HANDLE **Buffer > + ) > +{ > + EFI_STATUS Status; > + UINTN BufferSize; > + > + if (NumberHandles == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + BufferSize = 0; > + *NumberHandles = 0; > + *Buffer = NULL; > + Status = MmLocateHandle ( > + SearchType, > + Protocol, > + SearchKey, > + &BufferSize, > + *Buffer > + ); > + // > + // LocateHandleBuffer() returns incorrect status code if SearchType is > + // invalid. > + // > + // Add code to correctly handle expected errors from MmLocateHandle(). > + // > + if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { > + if (Status != EFI_INVALID_PARAMETER) { > + Status = EFI_NOT_FOUND; > + } > + return Status; > + } > + > + *Buffer = AllocatePool (BufferSize); > + if (*Buffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status = MmLocateHandle ( > + SearchType, > + Protocol, > + SearchKey, > + &BufferSize, > + *Buffer > + ); > + > + *NumberHandles = BufferSize / sizeof(EFI_HANDLE); > + if (EFI_ERROR(Status)) { > + *NumberHandles = 0; > + } > + > + return Status; > +} > diff --git a/StandaloneMmPkg/Core/Mmi.c b/StandaloneMmPkg/Core/Mmi.c > new file mode 100644 > index 0000000000..29aba7b53d > --- /dev/null > +++ b/StandaloneMmPkg/Core/Mmi.c > @@ -0,0 +1,337 @@ > +/** @file > + MMI management. > + > + Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +// > +// MM_HANDLER_STATE_NOTIFIER > +// > + > +// > +// MM_HANDLER - used for each MM handler > +// > + > +#define MMI_ENTRY_SIGNATURE SIGNATURE_32('m','m','i','e') > + > + typedef struct { > + UINTN Signature; > + LIST_ENTRY AllEntries; // All entries > + > + EFI_GUID HandlerType; // Type of interrupt > + LIST_ENTRY MmiHandlers; // All handlers > +} MMI_ENTRY; > + > +#define MMI_HANDLER_SIGNATURE SIGNATURE_32('m','m','i','h') > + > + typedef struct { > + UINTN Signature; > + LIST_ENTRY Link; // Link on MMI_ENTRY.MmiHandlers > + EFI_MM_HANDLER_ENTRY_POINT Handler; // The mm handler's entry point > + MMI_ENTRY *MmiEntry; > +} MMI_HANDLER; > + > +LIST_ENTRY mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList); > +LIST_ENTRY mMmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList); > + > +/** > + Finds the MMI entry for the requested handler type. > + > + @param HandlerType The type of the interrupt > + @param Create Create a new entry if not found > + > + @return MMI entry > + > +**/ > +MMI_ENTRY * > +EFIAPI > +MmCoreFindMmiEntry ( > + IN EFI_GUID *HandlerType, > + IN BOOLEAN Create > + ) > +{ > + LIST_ENTRY *Link; > + MMI_ENTRY *Item; > + MMI_ENTRY *MmiEntry; > + > + // > + // Search the MMI entry list for the matching GUID > + // > + MmiEntry = NULL; > + for (Link = mMmiEntryList.ForwardLink; > + Link != &mMmiEntryList; > + Link = Link->ForwardLink) { > + > + Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE); > + if (CompareGuid (&Item->HandlerType, HandlerType)) { > + // > + // This is the MMI entry > + // > + MmiEntry = Item; > + break; > + } > + } > + > + // > + // If the protocol entry was not found and Create is TRUE, then > + // allocate a new entry > + // > + if ((MmiEntry == NULL) && Create) { > + MmiEntry = AllocatePool (sizeof(MMI_ENTRY)); > + if (MmiEntry != NULL) { > + // > + // Initialize new MMI entry structure > + // > + MmiEntry->Signature = MMI_ENTRY_SIGNATURE; > + CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType); > + InitializeListHead (&MmiEntry->MmiHandlers); > + > + // > + // Add it to MMI entry list > + // > + InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries); > + } > + } > + return MmiEntry; > +} > + > +/** > + Manage MMI of a particular type. > + > + @param HandlerType Points to the handler type or NULL for root MMI handlers. > + @param Context Points to an optional context buffer. > + @param CommBuffer Points to the optional communication buffer. > + @param CommBufferSize Points to the size of the optional communication buffer. > + > + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced. > + @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced. > + @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced. > + @retval EFI_SUCCESS Interrupt source was handled and quiesced. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiManage ( > + IN CONST EFI_GUID *HandlerType, > + IN CONST VOID *Context OPTIONAL, > + IN OUT VOID *CommBuffer OPTIONAL, > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + LIST_ENTRY *Link; > + LIST_ENTRY *Head; > + MMI_ENTRY *MmiEntry; > + MMI_HANDLER *MmiHandler; > + BOOLEAN SuccessReturn; > + EFI_STATUS Status; > + > + Status = EFI_NOT_FOUND; > + SuccessReturn = FALSE; > + if (HandlerType == NULL) { > + // > + // Root MMI handler > + // > + > + Head = &mRootMmiHandlerList; > + } else { > + // > + // Non-root MMI handler > + // > + MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, FALSE); > + if (MmiEntry == NULL) { > + // > + // There is no handler registered for this interrupt source > + // > + return Status; > + } > + > + Head = &MmiEntry->MmiHandlers; > + } > + > + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { > + MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE); > + > + Status = MmiHandler->Handler ( > + (EFI_HANDLE) MmiHandler, > + Context, > + CommBuffer, > + CommBufferSize > + ); > + > + switch (Status) { > + case EFI_INTERRUPT_PENDING: > + // > + // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then > + // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned. > + // > + if (HandlerType != NULL) { > + return EFI_INTERRUPT_PENDING; > + } > + break; > + > + case EFI_SUCCESS: > + // > + // If at least one of the handlers returns EFI_SUCCESS then the function will return > + // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no > + // additional handlers will be processed. > + // > + if (HandlerType != NULL) { > + return EFI_SUCCESS; > + } > + SuccessReturn = TRUE; > + break; > + > + case EFI_WARN_INTERRUPT_SOURCE_QUIESCED: > + // > + // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED > + // then the function will return EFI_SUCCESS. > + // > + SuccessReturn = TRUE; > + break; > + > + case EFI_WARN_INTERRUPT_SOURCE_PENDING: > + // > + // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING > + // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned. > + // > + break; > + > + default: > + // > + // Unexpected status code returned. > + // > + ASSERT (FALSE); > + break; > + } > + } > + > + if (SuccessReturn) { > + Status = EFI_SUCCESS; > + } > + > + return Status; > +} > + > +/** > + Registers a handler to execute within MM. > + > + @param Handler Handler service funtion pointer. > + @param HandlerType Points to the handler type or NULL for root MMI handlers. > + @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function. > + > + @retval EFI_SUCCESS Handler register success. > + @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiHandlerRegister ( > + IN EFI_MM_HANDLER_ENTRY_POINT Handler, > + IN CONST EFI_GUID *HandlerType OPTIONAL, > + OUT EFI_HANDLE *DispatchHandle > + ) > +{ > + MMI_HANDLER *MmiHandler; > + MMI_ENTRY *MmiEntry; > + LIST_ENTRY *List; > + > + if (Handler == NULL || DispatchHandle == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER)); > + if (MmiHandler == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + MmiHandler->Signature = MMI_HANDLER_SIGNATURE; > + MmiHandler->Handler = Handler; > + > + if (HandlerType == NULL) { > + // > + // This is root MMI handler > + // > + MmiEntry = NULL; > + List = &mRootMmiHandlerList; > + } else { > + // > + // None root MMI handler > + // > + MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, TRUE); > + if (MmiEntry == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + List = &MmiEntry->MmiHandlers; > + } > + > + MmiHandler->MmiEntry = MmiEntry; > + InsertTailList (List, &MmiHandler->Link); > + > + *DispatchHandle = (EFI_HANDLE) MmiHandler; > + > + return EFI_SUCCESS; > +} > + > +/** > + Unregister a handler in MM. > + > + @param DispatchHandle The handle that was specified when the handler was registered. > + > + @retval EFI_SUCCESS Handler function was successfully unregistered. > + @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiHandlerUnRegister ( > + IN EFI_HANDLE DispatchHandle > + ) > +{ > + MMI_HANDLER *MmiHandler; > + MMI_ENTRY *MmiEntry; > + > + MmiHandler = (MMI_HANDLER *) DispatchHandle; > + > + if (MmiHandler == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) { > + return EFI_INVALID_PARAMETER; > + } > + > + MmiEntry = MmiHandler->MmiEntry; > + > + RemoveEntryList (&MmiHandler->Link); > + FreePool (MmiHandler); > + > + if (MmiEntry == NULL) { > + // > + // This is root MMI handler > + // > + return EFI_SUCCESS; > + } > + > + if (IsListEmpty (&MmiEntry->MmiHandlers)) { > + // > + // No handler registered for this interrupt now, remove the MMI_ENTRY > + // > + RemoveEntryList (&MmiEntry->AllEntries); > + > + FreePool (MmiEntry); > + } > + > + return EFI_SUCCESS; > +} > diff --git a/StandaloneMmPkg/Core/Notify.c b/StandaloneMmPkg/Core/Notify.c > new file mode 100644 > index 0000000000..d5fc8f50d1 > --- /dev/null > +++ b/StandaloneMmPkg/Core/Notify.c > @@ -0,0 +1,203 @@ > +/** @file > + Support functions for UEFI protocol notification infrastructure. > + > + Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +/** > + Signal event for every protocol in protocol entry. > + > + @param Prot Protocol interface > + > +**/ > +VOID > +MmNotifyProtocol ( > + IN PROTOCOL_INTERFACE *Prot > + ) > +{ > + PROTOCOL_ENTRY *ProtEntry; > + PROTOCOL_NOTIFY *ProtNotify; > + LIST_ENTRY *Link; > + > + ProtEntry = Prot->Protocol; > + for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { > + ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); > + ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle); > + } > +} > + > +/** > + Removes Protocol from the protocol list (but not the handle list). > + > + @param Handle The handle to remove protocol on. > + @param Protocol GUID of the protocol to be moved > + @param Interface The interface of the protocol > + > + @return Protocol Entry > + > +**/ > +PROTOCOL_INTERFACE * > +MmRemoveInterfaceFromProtocol ( > + IN IHANDLE *Handle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ) > +{ > + PROTOCOL_INTERFACE *Prot; > + PROTOCOL_NOTIFY *ProtNotify; > + PROTOCOL_ENTRY *ProtEntry; > + LIST_ENTRY *Link; > + > + Prot = MmFindProtocolInterface (Handle, Protocol, Interface); > + if (Prot != NULL) { > + > + ProtEntry = Prot->Protocol; > + > + // > + // If there's a protocol notify location pointing to this entry, back it up one > + // > + for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { > + ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); > + > + if (ProtNotify->Position == &Prot->ByProtocol) { > + ProtNotify->Position = Prot->ByProtocol.BackLink; > + } > + } > + > + // > + // Remove the protocol interface entry > + // > + RemoveEntryList (&Prot->ByProtocol); > + } > + > + return Prot; > +} > + > +/** > + Add a new protocol notification record for the request protocol. > + > + @param Protocol The requested protocol to add the notify > + registration > + @param Function Points to the notification function > + @param Registration Returns the registration record > + > + @retval EFI_SUCCESS Successfully returned the registration record > + that has been added or unhooked > + @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL > + @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request > + @retval EFI_NOT_FOUND If the registration is not found when Function == NULL > + > +**/ > +EFI_STATUS > +EFIAPI > +MmRegisterProtocolNotify ( > + IN CONST EFI_GUID *Protocol, > + IN EFI_MM_NOTIFY_FN Function, > + OUT VOID **Registration > + ) > +{ > + PROTOCOL_ENTRY *ProtEntry; > + PROTOCOL_NOTIFY *ProtNotify; > + LIST_ENTRY *Link; > + EFI_STATUS Status; > + > + if (Protocol == NULL || Registration == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Function == NULL) { > + // > + // Get the protocol entry per Protocol > + // > + ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE); > + if (ProtEntry != NULL) { > + ProtNotify = (PROTOCOL_NOTIFY * )*Registration; > + for (Link = ProtEntry->Notify.ForwardLink; > + Link != &ProtEntry->Notify; > + Link = Link->ForwardLink) { > + // > + // Compare the notification record > + // > + if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){ > + // > + // If Registration is an existing registration, then unhook it > + // > + ProtNotify->Signature = 0; > + RemoveEntryList (&ProtNotify->Link); > + FreePool (ProtNotify); > + return EFI_SUCCESS; > + } > + } > + } > + // > + // If the registration is not found > + // > + return EFI_NOT_FOUND; > + } > + > + ProtNotify = NULL; > + > + // > + // Get the protocol entry to add the notification too > + // > + ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE); > + if (ProtEntry != NULL) { > + // > + // Find whether notification already exist > + // > + for (Link = ProtEntry->Notify.ForwardLink; > + Link != &ProtEntry->Notify; > + Link = Link->ForwardLink) { > + > + ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); > + if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) && > + (ProtNotify->Function == Function)) { > + > + // > + // Notification already exist > + // > + *Registration = ProtNotify; > + > + return EFI_SUCCESS; > + } > + } > + > + // > + // Allocate a new notification record > + // > + ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY)); > + if (ProtNotify != NULL) { > + ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE; > + ProtNotify->Protocol = ProtEntry; > + ProtNotify->Function = Function; > + // > + // Start at the ending > + // > + ProtNotify->Position = ProtEntry->Protocols.BackLink; > + > + InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); > + } > + } > + > + // > + // Done. If we have a protocol notify entry, then return it. > + // Otherwise, we must have run out of resources trying to add one > + // > + Status = EFI_OUT_OF_RESOURCES; > + if (ProtNotify != NULL) { > + *Registration = ProtNotify; > + Status = EFI_SUCCESS; > + } > + return Status; > +} > diff --git a/StandaloneMmPkg/Core/Page.c b/StandaloneMmPkg/Core/Page.c > new file mode 100644 > index 0000000000..ba3e7cea74 > --- /dev/null > +++ b/StandaloneMmPkg/Core/Page.c > @@ -0,0 +1,384 @@ > +/** @file > + MM Memory page management functions. > + > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ > + ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size))) > + > +#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT) > + > +LIST_ENTRY mMmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap); > + > +UINTN mMapKey; > + > +/** > + Internal Function. Allocate n pages from given free page node. > + > + @param Pages The free page node. > + @param NumberOfPages Number of pages to be allocated. > + @param MaxAddress Request to allocate memory below this address. > + > + @return Memory address of allocated pages. > + > +**/ > +UINTN > +InternalAllocPagesOnOneNode ( > + IN OUT FREE_PAGE_LIST *Pages, > + IN UINTN NumberOfPages, > + IN UINTN MaxAddress > + ) > +{ > + UINTN Top; > + UINTN Bottom; > + FREE_PAGE_LIST *Node; > + > + Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages); > + if (Top > Pages->NumberOfPages) { > + Top = Pages->NumberOfPages; > + } > + Bottom = Top - NumberOfPages; > + > + if (Top < Pages->NumberOfPages) { > + Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top)); > + Node->NumberOfPages = Pages->NumberOfPages - Top; > + InsertHeadList (&Pages->Link, &Node->Link); > + } > + > + if (Bottom > 0) { > + Pages->NumberOfPages = Bottom; > + } else { > + RemoveEntryList (&Pages->Link); > + } > + > + return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom); > +} > + > +/** > + Internal Function. Allocate n pages from free page list below MaxAddress. > + > + @param FreePageList The free page node. > + @param NumberOfPages Number of pages to be allocated. > + @param MaxAddress Request to allocate memory below this address. > + > + @return Memory address of allocated pages. > + > +**/ > +UINTN > +InternalAllocMaxAddress ( > + IN OUT LIST_ENTRY *FreePageList, > + IN UINTN NumberOfPages, > + IN UINTN MaxAddress > + ) > +{ > + LIST_ENTRY *Node; > + FREE_PAGE_LIST *Pages; > + > + for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) { > + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); > + if (Pages->NumberOfPages >= NumberOfPages && > + (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) { > + return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress); > + } > + } > + return (UINTN)(-1); > +} > + > +/** > + Internal Function. Allocate n pages from free page list at given address. > + > + @param FreePageList The free page node. > + @param NumberOfPages Number of pages to be allocated. > + @param MaxAddress Request to allocate memory below this address. > + > + @return Memory address of allocated pages. > + > +**/ > +UINTN > +InternalAllocAddress ( > + IN OUT LIST_ENTRY *FreePageList, > + IN UINTN NumberOfPages, > + IN UINTN Address > + ) > +{ > + UINTN EndAddress; > + LIST_ENTRY *Node; > + FREE_PAGE_LIST *Pages; > + > + if ((Address & EFI_PAGE_MASK) != 0) { > + return ~Address; > + } > + > + EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages); > + for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) { > + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); > + if ((UINTN)Pages <= Address) { > + if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) { > + break; > + } > + return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress); > + } > + } > + return ~Address; > +} > + > +/** > + Allocates pages from the memory map. > + > + @param Type The type of allocation to perform. > + @param MemoryType The type of memory to turn the allocated pages > + into. > + @param NumberOfPages The number of pages to allocate. > + @param Memory A pointer to receive the base allocated memory > + address. > + > + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. > + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. > + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. > + @retval EFI_SUCCESS Pages successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalAllocatePages ( > + IN EFI_ALLOCATE_TYPE Type, > + IN EFI_MEMORY_TYPE MemoryType, > + IN UINTN NumberOfPages, > + OUT EFI_PHYSICAL_ADDRESS *Memory > + ) > +{ > + UINTN RequestedAddress; > + > + if (MemoryType != EfiRuntimeServicesCode && > + MemoryType != EfiRuntimeServicesData) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // We don't track memory type in MM > + // > + RequestedAddress = (UINTN)*Memory; > + switch (Type) { > + case AllocateAnyPages: > + RequestedAddress = (UINTN)(-1); > + case AllocateMaxAddress: > + *Memory = InternalAllocMaxAddress ( > + &mMmMemoryMap, > + NumberOfPages, > + RequestedAddress > + ); > + if (*Memory == (UINTN)-1) { > + return EFI_OUT_OF_RESOURCES; > + } > + break; > + case AllocateAddress: > + *Memory = InternalAllocAddress ( > + &mMmMemoryMap, > + NumberOfPages, > + RequestedAddress > + ); > + if (*Memory != RequestedAddress) { > + return EFI_NOT_FOUND; > + } > + break; > + default: > + return EFI_INVALID_PARAMETER; > + } > + return EFI_SUCCESS; > +} > + > +/** > + Allocates pages from the memory map. > + > + @param Type The type of allocation to perform. > + @param MemoryType The type of memory to turn the allocated pages > + into. > + @param NumberOfPages The number of pages to allocate. > + @param Memory A pointer to receive the base allocated memory > + address. > + > + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. > + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. > + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. > + @retval EFI_SUCCESS Pages successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmAllocatePages ( > + IN EFI_ALLOCATE_TYPE Type, > + IN EFI_MEMORY_TYPE MemoryType, > + IN UINTN NumberOfPages, > + OUT EFI_PHYSICAL_ADDRESS *Memory > + ) > +{ > + EFI_STATUS Status; > + > + Status = MmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory); > + return Status; > +} > + > +/** > + Internal Function. Merge two adjacent nodes. > + > + @param First The first of two nodes to merge. > + > + @return Pointer to node after merge (if success) or pointer to next node (if fail). > + > +**/ > +FREE_PAGE_LIST * > +InternalMergeNodes ( > + IN FREE_PAGE_LIST *First > + ) > +{ > + FREE_PAGE_LIST *Next; > + > + Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link); > + ASSERT ( > + TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages); > + > + if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) { > + First->NumberOfPages += Next->NumberOfPages; > + RemoveEntryList (&Next->Link); > + Next = First; > + } > + return Next; > +} > + > +/** > + Frees previous allocated pages. > + > + @param Memory Base address of memory being freed. > + @param NumberOfPages The number of pages to free. > + > + @retval EFI_NOT_FOUND Could not find the entry that covers the range. > + @retval EFI_INVALID_PARAMETER Address not aligned. > + @return EFI_SUCCESS Pages successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalFreePages ( > + IN EFI_PHYSICAL_ADDRESS Memory, > + IN UINTN NumberOfPages > + ) > +{ > + LIST_ENTRY *Node; > + FREE_PAGE_LIST *Pages; > + > + if ((Memory & EFI_PAGE_MASK) != 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + Pages = NULL; > + Node = mMmMemoryMap.ForwardLink; > + while (Node != &mMmMemoryMap) { > + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); > + if (Memory < (UINTN)Pages) { > + break; > + } > + Node = Node->ForwardLink; > + } > + > + if (Node != &mMmMemoryMap && > + Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Node->BackLink != &mMmMemoryMap) { > + Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link); > + if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) { > + return EFI_INVALID_PARAMETER; > + } > + } > + > + Pages = (FREE_PAGE_LIST*)(UINTN)Memory; > + Pages->NumberOfPages = NumberOfPages; > + InsertTailList (Node, &Pages->Link); > + > + if (Pages->Link.BackLink != &mMmMemoryMap) { > + Pages = InternalMergeNodes ( > + BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link) > + ); > + } > + > + if (Node != &mMmMemoryMap) { > + InternalMergeNodes (Pages); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Frees previous allocated pages. > + > + @param Memory Base address of memory being freed. > + @param NumberOfPages The number of pages to free. > + > + @retval EFI_NOT_FOUND Could not find the entry that covers the range. > + @retval EFI_INVALID_PARAMETER Address not aligned. > + @return EFI_SUCCESS Pages successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFreePages ( > + IN EFI_PHYSICAL_ADDRESS Memory, > + IN UINTN NumberOfPages > + ) > +{ > + EFI_STATUS Status; > + > + Status = MmInternalFreePages (Memory, NumberOfPages); > + return Status; > +} > + > +/** > + Add free MMRAM region for use by memory service. > + > + @param MemBase Base address of memory region. > + @param MemLength Length of the memory region. > + @param Type Memory type. > + @param Attributes Memory region state. > + > +**/ > +VOID > +MmAddMemoryRegion ( > + IN EFI_PHYSICAL_ADDRESS MemBase, > + IN UINT64 MemLength, > + IN EFI_MEMORY_TYPE Type, > + IN UINT64 Attributes > + ) > +{ > + UINTN AlignedMemBase; > + > + // > + // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization > + // > + if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { > + return; > + } > + > + // > + // Align range on an EFI_PAGE_SIZE boundary > + // > + AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; > + MemLength -= AlignedMemBase - MemBase; > + MmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength)); > +} > diff --git a/StandaloneMmPkg/Core/Pool.c b/StandaloneMmPkg/Core/Pool.c > new file mode 100644 > index 0000000000..bdf1258381 > --- /dev/null > +++ b/StandaloneMmPkg/Core/Pool.c > @@ -0,0 +1,287 @@ > +/** @file > + SMM Memory pool management functions. > + > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX]; > +// > +// To cache the MMRAM base since when Loading modules At fixed address feature is enabled, > +// all module is assigned an offset relative the MMRAM base in build time. > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0; > + > +/** > + Called to initialize the memory service. > + > + @param MmramRangeCount Number of MMRAM Regions > + @param MmramRanges Pointer to MMRAM Descriptors > + > +**/ > +VOID > +MmInitializeMemoryServices ( > + IN UINTN MmramRangeCount, > + IN EFI_MMRAM_DESCRIPTOR *MmramRanges > + ) > +{ > + UINTN Index; > + > + // > + // Initialize Pool list > + // > + for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) { > + InitializeListHead (&mMmPoolLists[--Index]); > + } > + > + > + // > + // Initialize free MMRAM regions > + // > + for (Index = 0; Index < MmramRangeCount; Index++) { > + // > + // BUGBUG: Add legacy MMRAM region is buggy. > + // > + if (MmramRanges[Index].CpuStart < BASE_1MB) { > + continue; > + } > + DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n", Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize)); > + MmAddMemoryRegion ( > + MmramRanges[Index].CpuStart, > + MmramRanges[Index].PhysicalSize, > + EfiConventionalMemory, > + MmramRanges[Index].RegionState > + ); > + } > + > +} > + > +/** > + Internal Function. Allocate a pool by specified PoolIndex. > + > + @param PoolIndex Index which indicate the Pool size. > + @param FreePoolHdr The returned Free pool. > + > + @retval EFI_OUT_OF_RESOURCES Allocation failed. > + @retval EFI_SUCCESS Pool successfully allocated. > + > +**/ > +EFI_STATUS > +InternalAllocPoolByIndex ( > + IN UINTN PoolIndex, > + OUT FREE_POOL_HEADER **FreePoolHdr > + ) > +{ > + EFI_STATUS Status; > + FREE_POOL_HEADER *Hdr; > + EFI_PHYSICAL_ADDRESS Address; > + > + ASSERT (PoolIndex <= MAX_POOL_INDEX); > + Status = EFI_SUCCESS; > + Hdr = NULL; > + if (PoolIndex == MAX_POOL_INDEX) { > + Status = MmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + Hdr = (FREE_POOL_HEADER *) (UINTN) Address; > + } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) { > + Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link); > + RemoveEntryList (&Hdr->Link); > + } else { > + Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr); > + if (!EFI_ERROR (Status)) { > + Hdr->Header.Size >>= 1; > + Hdr->Header.Available = TRUE; > + InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link); > + Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size); > + } > + } > + > + if (!EFI_ERROR (Status)) { > + Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex; > + Hdr->Header.Available = FALSE; > + } > + > + *FreePoolHdr = Hdr; > + return Status; > +} > + > +/** > + Internal Function. Free a pool by specified PoolIndex. > + > + @param FreePoolHdr The pool to free. > + > + @retval EFI_SUCCESS Pool successfully freed. > + > +**/ > +EFI_STATUS > +InternalFreePoolByIndex ( > + IN FREE_POOL_HEADER *FreePoolHdr > + ) > +{ > + UINTN PoolIndex; > + > + ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0); > + ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0); > + ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE); > + > + PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT); > + FreePoolHdr->Header.Available = TRUE; > + ASSERT (PoolIndex < MAX_POOL_INDEX); > + InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link); > + return EFI_SUCCESS; > +} > + > +/** > + Allocate pool of a particular type. > + > + @param PoolType Type of pool to allocate. > + @param Size The amount of pool to allocate. > + @param Buffer The address to return a pointer to the allocated > + pool. > + > + @retval EFI_INVALID_PARAMETER PoolType not valid. > + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. > + @retval EFI_SUCCESS Pool successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalAllocatePool ( > + IN EFI_MEMORY_TYPE PoolType, > + IN UINTN Size, > + OUT VOID **Buffer > + ) > +{ > + POOL_HEADER *PoolHdr; > + FREE_POOL_HEADER *FreePoolHdr; > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS Address; > + UINTN PoolIndex; > + > + if (PoolType != EfiRuntimeServicesCode && > + PoolType != EfiRuntimeServicesData) { > + return EFI_INVALID_PARAMETER; > + } > + > + Size += sizeof (*PoolHdr); > + if (Size > MAX_POOL_SIZE) { > + Size = EFI_SIZE_TO_PAGES (Size); > + Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + PoolHdr = (POOL_HEADER*)(UINTN)Address; > + PoolHdr->Size = EFI_PAGES_TO_SIZE (Size); > + PoolHdr->Available = FALSE; > + *Buffer = PoolHdr + 1; > + return Status; > + } > + > + Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT; > + PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size); > + if ((Size & (Size - 1)) != 0) { > + PoolIndex++; > + } > + > + Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr); > + if (!EFI_ERROR(Status)) { > + *Buffer = &FreePoolHdr->Header + 1; > + } > + return Status; > +} > + > +/** > + Allocate pool of a particular type. > + > + @param PoolType Type of pool to allocate. > + @param Size The amount of pool to allocate. > + @param Buffer The address to return a pointer to the allocated > + pool. > + > + @retval EFI_INVALID_PARAMETER PoolType not valid. > + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. > + @retval EFI_SUCCESS Pool successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmAllocatePool ( > + IN EFI_MEMORY_TYPE PoolType, > + IN UINTN Size, > + OUT VOID **Buffer > + ) > +{ > + EFI_STATUS Status; > + > + Status = MmInternalAllocatePool (PoolType, Size, Buffer); > + return Status; > +} > + > +/** > + Frees pool. > + > + @param Buffer The allocated pool entry to free. > + > + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. > + @retval EFI_SUCCESS Pool successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalFreePool ( > + IN VOID *Buffer > + ) > +{ > + FREE_POOL_HEADER *FreePoolHdr; > + > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1); > + ASSERT (!FreePoolHdr->Header.Available); > + > + if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { > + ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0); > + ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0); > + return MmInternalFreePages ( > + (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr, > + EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size) > + ); > + } > + return InternalFreePoolByIndex (FreePoolHdr); > +} > + > +/** > + Frees pool. > + > + @param Buffer The allocated pool entry to free. > + > + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. > + @retval EFI_SUCCESS Pool successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFreePool ( > + IN VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + > + Status = MmInternalFreePool (Buffer); > + return Status; > +} > diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.c b/StandaloneMmPkg/Core/StandaloneMmCore.c > new file mode 100644 > index 0000000000..0bb99b9710 > --- /dev/null > +++ b/StandaloneMmPkg/Core/StandaloneMmCore.c > @@ -0,0 +1,708 @@ > +/** @file > + MM Core Main Entry Point > + > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "StandaloneMmCore.h" > + > +EFI_STATUS > +MmCoreFfsFindMmDriver ( > + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader > + ); > + > +EFI_STATUS > +MmDispatcher ( > + VOID > + ); > + > +// > +// Globals used to initialize the protocol > +// > +EFI_HANDLE mMmCpuHandle = NULL; > + > +// > +// Physical pointer to private structure shared between MM IPL and the MM Core > +// > +MM_CORE_PRIVATE_DATA *gMmCorePrivate; > + > +// > +// MM Core global variable for MM System Table. Only accessed as a physical structure in MMRAM. > +// > +EFI_MM_SYSTEM_TABLE gMmCoreMmst = { > + > + // The table header for the MMST. > + { > + MM_MMST_SIGNATURE, > + EFI_MM_SYSTEM_TABLE_REVISION, > + sizeof (gMmCoreMmst.Hdr) > + }, > + // MmFirmwareVendor > + NULL, > + // MmFirmwareRevision > + 0, > + // MmInstallConfigurationTable > + MmInstallConfigurationTable, > + // I/O Service > + { > + { > + (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmMemRead > + (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmMemWrite > + }, > + { > + (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmIoRead > + (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmIoWrite > + } > + }, > + // Runtime memory services > + MmAllocatePool, > + MmFreePool, > + MmAllocatePages, > + MmFreePages, > + // MP service > + NULL, // MmStartupThisAp > + 0, // CurrentlyExecutingCpu > + 0, // NumberOfCpus > + NULL, // CpuSaveStateSize > + NULL, // CpuSaveState > + 0, // NumberOfTableEntries > + NULL, // MmConfigurationTable > + MmInstallProtocolInterface, > + MmUninstallProtocolInterface, > + MmHandleProtocol, > + MmRegisterProtocolNotify, > + MmLocateHandle, > + MmLocateProtocol, > + MmiManage, > + MmiHandlerRegister, > + MmiHandlerUnRegister > +}; > + > +// > +// Flag to determine if the platform has performed a legacy boot. > +// If this flag is TRUE, then the runtime code and runtime data associated with the > +// MM IPL are converted to free memory, so the MM Core must guarantee that is > +// does not touch of the code/data associated with the MM IPL if this flag is TRUE. > +// > +BOOLEAN mInLegacyBoot = FALSE; > + > +// > +// Table of MMI Handlers that are registered by the MM Core when it is initialized > +// > +MM_CORE_MMI_HANDLERS mMmCoreMmiHandlers[] = { > + { MmFvDispatchHandler, &gMmFvDispatchGuid, NULL, TRUE }, > + { MmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE }, > + { MmReadyToLockHandler, &gEfiDxeMmReadyToLockProtocolGuid, NULL, TRUE }, > + { MmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, FALSE }, > + { MmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE }, > + { MmExitBootServiceHandler,&gEfiEventExitBootServicesGuid, NULL, FALSE }, > + { MmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE }, > + { NULL, NULL, NULL, FALSE }, > +}; > + > +EFI_SYSTEM_TABLE *mEfiSystemTable; > +UINTN mMmramRangeCount; > +EFI_MMRAM_DESCRIPTOR *mMmramRanges; > + > +/** > + Place holder function until all the MM System Table Service are available. > + > + Note: This function is only used by MMRAM invocation. It is never used by DXE invocation. > + > + @param Arg1 Undefined > + @param Arg2 Undefined > + @param Arg3 Undefined > + @param Arg4 Undefined > + @param Arg5 Undefined > + > + @return EFI_NOT_AVAILABLE_YET > + > +**/ > +EFI_STATUS > +EFIAPI > +MmEfiNotAvailableYetArg5 ( > + UINTN Arg1, > + UINTN Arg2, > + UINTN Arg3, > + UINTN Arg4, > + UINTN Arg5 > + ) > +{ > + // > + // This function should never be executed. If it does, then the architectural protocols > + // have not been designed correctly. > + // > + return EFI_NOT_AVAILABLE_YET; > +} > + > +/** > + Software MMI handler that is called when a Legacy Boot event is signaled. The MM > + Core uses this signal to know that a Legacy Boot has been performed and that > + gMmCorePrivate that is shared between the UEFI and MM execution environments can > + not be accessed from MM anymore since that structure is considered free memory by > + a legacy OS. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLegacyBootHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_HANDLE MmHandle; > + EFI_STATUS Status = EFI_SUCCESS; > + > + if (!mInLegacyBoot) { > + MmHandle = NULL; > + Status = MmInstallProtocolInterface ( > + &MmHandle, > + &gEfiEventLegacyBootGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + } > + mInLegacyBoot = TRUE; > + return Status; > +} > + > +/** > + Software MMI handler that is called when a ExitBoot Service event is signaled. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmExitBootServiceHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_HANDLE MmHandle; > + EFI_STATUS Status = EFI_SUCCESS; > + STATIC BOOLEAN mInExitBootServices = FALSE; > + > + if (!mInExitBootServices) { > + MmHandle = NULL; > + Status = MmInstallProtocolInterface ( > + &MmHandle, > + &gEfiEventExitBootServicesGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + } > + mInExitBootServices = TRUE; > + return Status; > +} > + > +/** > + Software MMI handler that is called when a ExitBoot Service event is signaled. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmReadyToBootHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_HANDLE MmHandle; > + EFI_STATUS Status = EFI_SUCCESS; > + STATIC BOOLEAN mInReadyToBoot = FALSE; > + > + if (!mInReadyToBoot) { > + MmHandle = NULL; > + Status = MmInstallProtocolInterface ( > + &MmHandle, > + &gEfiEventReadyToBootGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + } > + mInReadyToBoot = TRUE; > + return Status; > +} > + > +/** > + Software MMI handler that is called when the DxeMmReadyToLock protocol is added > + or if gEfiEventReadyToBootGuid is signaled. This function unregisters the > + Software SMIs that are nor required after MMRAM is locked and installs the > + MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about > + to be locked. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmReadyToLockHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + EFI_HANDLE MmHandle; > + > + DEBUG ((DEBUG_INFO, "MmReadyToLockHandler\n")); > + > + // > + // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped > + // > + for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) { > + if (mMmCoreMmiHandlers[Index].UnRegister) { > + MmiHandlerUnRegister (mMmCoreMmiHandlers[Index].DispatchHandle); > + } > + } > + > + // > + // Install MM Ready to lock protocol > + // > + MmHandle = NULL; > + Status = MmInstallProtocolInterface ( > + &MmHandle, > + &gEfiMmReadyToLockProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + > + // > + // Make sure MM CPU I/O 2 Protocol has been installed into the handle database > + // > + //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface); > + > + // > + // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed > + // > + //if (EFI_ERROR (Status)) { > + //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n")); > + //} > + > + > + // > + // Assert if the CPU I/O 2 Protocol is not installed > + // > + //ASSERT_EFI_ERROR (Status); > + > + // > + // Display any drivers that were not dispatched because dependency expression > + // evaluated to false if this is a debug build > + // > + //MmDisplayDiscoveredNotDispatched (); > + > + return Status; > +} > + > +/** > + Software MMI handler that is called when the EndOfDxe event is signaled. > + This function installs the MM EndOfDxe Protocol so MM Drivers are informed that > + platform code will invoke 3rd part code. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmEndOfDxeHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE MmHandle; > + > + DEBUG ((DEBUG_INFO, "MmEndOfDxeHandler\n")); > + // > + // Install MM EndOfDxe protocol > + // > + MmHandle = NULL; > + Status = MmInstallProtocolInterface ( > + &MmHandle, > + &gEfiMmEndOfDxeProtocolGuid, > + EFI_NATIVE_INTERFACE, > + NULL > + ); > + return Status; > +} > + > + > + > +/** > + The main entry point to MM Foundation. > + > + Note: This function is only used by MMRAM invocation. It is never used by DXE invocation. > + > + @param MmEntryContext Processor information and functionality > + needed by MM Foundation. > + > +**/ > +VOID > +EFIAPI > +MmEntryPoint ( > + IN CONST EFI_MM_ENTRY_CONTEXT *MmEntryContext > +) > +{ > + EFI_STATUS Status; > + EFI_MM_COMMUNICATE_HEADER *CommunicateHeader; > + BOOLEAN InLegacyBoot; > + > + DEBUG ((DEBUG_INFO, "MmEntryPoint ...\n")); > + > + // > + // Update MMST using the context > + // > + CopyMem (&gMmCoreMmst.MmStartupThisAp, MmEntryContext, sizeof (EFI_MM_ENTRY_CONTEXT)); > + > + // > + // Call platform hook before Mm Dispatch > + // > + //PlatformHookBeforeMmDispatch (); > + > + // > + // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed > + // > + InLegacyBoot = mInLegacyBoot; > + if (!InLegacyBoot) { > + // > + // TBD: Mark the InMm flag as TRUE > + // > + gMmCorePrivate->InMm = TRUE; > + > + // > + // Check to see if this is a Synchronous MMI sent through the MM Communication > + // Protocol or an Asynchronous MMI > + // > + if (gMmCorePrivate->CommunicationBuffer != 0) { > + // > + // Synchronous MMI for MM Core or request from Communicate protocol > + // > + if (!MmIsBufferOutsideMmValid ((UINTN)gMmCorePrivate->CommunicationBuffer, gMmCorePrivate->BufferSize)) { > + // > + // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER > + // > + gMmCorePrivate->CommunicationBuffer = 0; > + gMmCorePrivate->ReturnStatus = EFI_INVALID_PARAMETER; > + } else { > + CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)gMmCorePrivate->CommunicationBuffer; > + gMmCorePrivate->BufferSize -= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data); > + //DEBUG ((DEBUG_INFO, "CommunicateHeader->HeaderGuid - %g\n", &CommunicateHeader->HeaderGuid)); > + Status = MmiManage ( > + &CommunicateHeader->HeaderGuid, > + NULL, > + CommunicateHeader->Data, > + (UINTN *)&gMmCorePrivate->BufferSize > + ); > + // > + // Update CommunicationBuffer, BufferSize and ReturnStatus > + // Communicate service finished, reset the pointer to CommBuffer to NULL > + // > + gMmCorePrivate->BufferSize += OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data); > + gMmCorePrivate->CommunicationBuffer = 0; > + gMmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND; > + } > + } > + } > + > + // > + // Process Asynchronous MMI sources > + // > + MmiManage (NULL, NULL, NULL, NULL); > + > + // > + // TBD: Do not use private data structure ? > + // > + > + // > + // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed > + // > + if (!InLegacyBoot) { > + // > + // Clear the InMm flag as we are going to leave MM > + // > + gMmCorePrivate->InMm = FALSE; > + } > + > + DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n")); > +} > + > +EFI_STATUS > +EFIAPI > +MmConfigurationMmNotify ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + EFI_MM_CONFIGURATION_PROTOCOL *MmConfiguration; > + > + DEBUG ((DEBUG_INFO, "MmConfigurationMmNotify(%g) - %x\n", Protocol, Interface)); > + > + MmConfiguration = Interface; > + > + // > + // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol > + // > + Status = MmConfiguration->RegisterMmEntry (MmConfiguration, (EFI_MM_ENTRY_POINT)(UINTN)gMmCorePrivate->MmEntryPoint); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Set flag to indicate that the MM Entry Point has been registered which > + // means that MMIs are now fully operational. > + // > + gMmCorePrivate->MmEntryPointRegistered = TRUE; > + > + // > + // Print debug message showing MM Core entry point address. > + // > + DEBUG ((DEBUG_INFO, "MM Core registered MM Entry Point address %p\n", (VOID *)(UINTN)gMmCorePrivate->MmEntryPoint)); > + return EFI_SUCCESS; > +} > + > +UINTN > +GetHobListSize ( > + IN VOID *HobStart > + ) > +{ > + EFI_PEI_HOB_POINTERS Hob; > + > + ASSERT (HobStart != NULL); > + > + Hob.Raw = (UINT8 *) HobStart; > + while (!END_OF_HOB_LIST (Hob)) { > + Hob.Raw = GET_NEXT_HOB (Hob); > + } > + // > + // Need plus END_OF_HOB_LIST > + // > + return (UINTN)Hob.Raw - (UINTN)HobStart + sizeof(EFI_HOB_GENERIC_HEADER); > +} > + > +/** > + The Entry Point for MM Core > + > + Install DXE Protocols and reload MM Core into MMRAM and register MM Core > + EntryPoint on the MMI vector. > + > + Note: This function is called for both DXE invocation and MMRAM invocation. > + > + @param ImageHandle The firmware allocated handle for the EFI image. > + @param SystemTable A pointer to the EFI System Table. > + > + @retval EFI_SUCCESS The entry point is executed successfully. > + @retval Other Some error occurred when executing this entry point. > + > +**/ > +EFI_STATUS > +EFIAPI > +StandaloneMmMain ( > + IN VOID *HobStart > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + VOID *MmHobStart; > + UINTN HobSize; > + VOID *Registration; > + EFI_HOB_GUID_TYPE *GuidHob; > + MM_CORE_DATA_HOB_DATA *DataInHob; > + EFI_HOB_GUID_TYPE *MmramRangesHob; > + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData; > + EFI_MMRAM_DESCRIPTOR *MmramRanges; > + UINT32 MmramRangeCount; > + EFI_HOB_FIRMWARE_VOLUME *BfvHob; > + > + ProcessLibraryConstructorList (HobStart, &gMmCoreMmst); > + > + DEBUG ((DEBUG_INFO, "MmMain - 0x%x\n", HobStart)); > + > + // > + // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA > + // structure in the Hoblist. This choice will govern how boot information is > + // extracted later. > + // > + GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart); > + if (GuidHob == NULL) { > + // > + // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then > + // initialise it > + // > + gMmCorePrivate = (MM_CORE_PRIVATE_DATA *) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof(MM_CORE_PRIVATE_DATA))); > + SetMem ((VOID *)(UINTN)gMmCorePrivate, sizeof(MM_CORE_PRIVATE_DATA), 0); > + gMmCorePrivate->Signature = MM_CORE_PRIVATE_DATA_SIGNATURE; > + gMmCorePrivate->MmEntryPointRegistered = FALSE; > + gMmCorePrivate->InMm = FALSE; > + gMmCorePrivate->ReturnStatus = EFI_SUCCESS; > + > + // > + // Extract the MMRAM ranges from the MMRAM descriptor HOB > + // > + MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart); > + if (MmramRangesHob == NULL) > + return EFI_UNSUPPORTED; > + > + MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob); > + ASSERT (MmramRangesHobData != NULL); > + MmramRanges = MmramRangesHobData->Descriptor; > + MmramRangeCount = MmramRangesHobData->NumberOfMmReservedRegions; > + ASSERT (MmramRanges); > + ASSERT (MmramRangeCount); > + > + // > + // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any > + // code relies on them being present there > + // > + gMmCorePrivate->MmramRangeCount = MmramRangeCount; > + gMmCorePrivate->MmramRanges = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (MmramRangeCount * sizeof(EFI_MMRAM_DESCRIPTOR)); > + ASSERT (gMmCorePrivate->MmramRanges != 0); > + CopyMem ((VOID *)(UINTN)gMmCorePrivate->MmramRanges, > + MmramRanges, > + MmramRangeCount * sizeof(EFI_MMRAM_DESCRIPTOR)); > + } else { > + DataInHob = GET_GUID_HOB_DATA (GuidHob); > + gMmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address; > + MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges; > + MmramRangeCount = gMmCorePrivate->MmramRangeCount; > + } > + > + // > + // Print the MMRAM ranges passed by the caller > + // > + DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount)); > + for (Index = 0; Index < MmramRangeCount; Index++) { > + DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index, > + MmramRanges[Index].CpuStart, > + MmramRanges[Index].PhysicalSize)); > + } > + > + // > + // Copy the MMRAM ranges into private MMRAM > + // > + mMmramRangeCount = MmramRangeCount; > + DEBUG ((DEBUG_INFO, "mMmramRangeCount - 0x%x\n", mMmramRangeCount)); > + mMmramRanges = AllocatePool (mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)); > + DEBUG ((DEBUG_INFO, "mMmramRanges - 0x%x\n", mMmramRanges)); > + ASSERT (mMmramRanges != NULL); > + CopyMem (mMmramRanges, (VOID *)(UINTN)MmramRanges, mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)); > + > + // > + // Get Boot Firmware Volume address from the BFV Hob > + // > + BfvHob = GetFirstHob (EFI_HOB_TYPE_FV); > + if (BfvHob != NULL) { > + DEBUG ((DEBUG_INFO, "BFV address - 0x%x\n", BfvHob->BaseAddress)); > + DEBUG ((DEBUG_INFO, "BFV size - 0x%x\n", BfvHob->Length)); > + gMmCorePrivate->StandaloneBfvAddress = BfvHob->BaseAddress; > + } > + > + gMmCorePrivate->Mmst = (EFI_PHYSICAL_ADDRESS)(UINTN)&gMmCoreMmst; > + gMmCorePrivate->MmEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)MmEntryPoint; > + > + // > + // No need to initialize memory service. > + // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(), > + // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor. > + // > + > + DEBUG ((DEBUG_INFO, "MmInstallConfigurationTable For HobList\n")); > + // > + // Install HobList > + // > + HobSize = GetHobListSize (HobStart); > + DEBUG ((DEBUG_INFO, "HobSize - 0x%x\n", HobSize)); > + MmHobStart = AllocatePool (HobSize); > + DEBUG ((DEBUG_INFO, "MmHobStart - 0x%x\n", MmHobStart)); > + ASSERT (MmHobStart != NULL); > + CopyMem (MmHobStart, HobStart, HobSize); > + Status = MmInstallConfigurationTable (&gMmCoreMmst, &gEfiHobListGuid, MmHobStart, HobSize); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and > + // use it to register the MM Foundation entrypoint > + // > + DEBUG ((DEBUG_INFO, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n")); > + Status = MmRegisterProtocolNotify ( > + &gEfiMmConfigurationProtocolGuid, > + MmConfigurationMmNotify, > + &Registration > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Dispatch standalone BFV > + // > + DEBUG ((DEBUG_INFO, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate->StandaloneBfvAddress)); > + if (gMmCorePrivate->StandaloneBfvAddress != 0) { > + MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)gMmCorePrivate->StandaloneBfvAddress); > + MmDispatcher (); > + } > + > + // > + // Register all handlers in the core table > + // > + for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) { > + Status = MmiHandlerRegister(mMmCoreMmiHandlers[Index].Handler, > + mMmCoreMmiHandlers[Index].HandlerType, > + &mMmCoreMmiHandlers[Index].DispatchHandle); > + DEBUG ((DEBUG_INFO, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers[Index].HandlerType, Status)); > + } > + > + DEBUG ((DEBUG_INFO, "MmMain Done!\n")); > + > + return EFI_SUCCESS; > +} > diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.h b/StandaloneMmPkg/Core/StandaloneMmCore.h > new file mode 100644 > index 0000000000..53921b7844 > --- /dev/null > +++ b/StandaloneMmPkg/Core/StandaloneMmCore.h > @@ -0,0 +1,903 @@ > +/** @file > + The internal header file includes the common header files, defines > + internal structure and functions used by MmCore module. > + > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef _MM_CORE_H_ > +#define _MM_CORE_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 "StandaloneMmCorePrivateData.h" > + > +// > +// Used to build a table of MMI Handlers that the MM Core registers > +// > +typedef struct { > + EFI_MM_HANDLER_ENTRY_POINT Handler; > + EFI_GUID *HandlerType; > + EFI_HANDLE DispatchHandle; > + BOOLEAN UnRegister; > +} MM_CORE_MMI_HANDLERS; > + > +// > +// Structure for recording the state of an MM Driver > +// > +#define EFI_MM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v') > + > +typedef struct { > + UINTN Signature; > + LIST_ENTRY Link; // mDriverList > + > + LIST_ENTRY ScheduledLink; // mScheduledQueue > + > + EFI_HANDLE FvHandle; > + EFI_GUID FileName; > + VOID *Pe32Data; > + UINTN Pe32DataSize; > + > + VOID *Depex; > + UINTN DepexSize; > + > + BOOLEAN Before; > + BOOLEAN After; > + EFI_GUID BeforeAfterGuid; > + > + BOOLEAN Dependent; > + BOOLEAN Scheduled; > + BOOLEAN Initialized; > + BOOLEAN DepexProtocolError; > + > + EFI_HANDLE ImageHandle; > + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; > + // > + // Image EntryPoint in MMRAM > + // > + PHYSICAL_ADDRESS ImageEntryPoint; > + // > + // Image Buffer in MMRAM > + // > + PHYSICAL_ADDRESS ImageBuffer; > + // > + // Image Page Number > + // > + UINTN NumberOfPage; > +} EFI_MM_DRIVER_ENTRY; > + > +#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l') > + > +/// > +/// IHANDLE - contains a list of protocol handles > +/// > +typedef struct { > + UINTN Signature; > + /// All handles list of IHANDLE > + LIST_ENTRY AllHandles; > + /// List of PROTOCOL_INTERFACE's for this handle > + LIST_ENTRY Protocols; > + UINTN LocateRequest; > +} IHANDLE; > + > +#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE) > + > +#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e') > + > +/// > +/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol > +/// database. Each handler that supports this protocol is listed, along > +/// with a list of registered notifies. > +/// > +typedef struct { > + UINTN Signature; > + /// Link Entry inserted to mProtocolDatabase > + LIST_ENTRY AllEntries; > + /// ID of the protocol > + EFI_GUID ProtocolID; > + /// All protocol interfaces > + LIST_ENTRY Protocols; > + /// Registerd notification handlers > + LIST_ENTRY Notify; > +} PROTOCOL_ENTRY; > + > +#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c') > + > +/// > +/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked > +/// with a protocol interface structure > +/// > +typedef struct { > + UINTN Signature; > + /// Link on IHANDLE.Protocols > + LIST_ENTRY Link; > + /// Back pointer > + IHANDLE *Handle; > + /// Link on PROTOCOL_ENTRY.Protocols > + LIST_ENTRY ByProtocol; > + /// The protocol ID > + PROTOCOL_ENTRY *Protocol; > + /// The interface value > + VOID *Interface; > +} PROTOCOL_INTERFACE; > + > +#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n') > + > +/// > +/// PROTOCOL_NOTIFY - used for each register notification for a protocol > +/// > +typedef struct { > + UINTN Signature; > + PROTOCOL_ENTRY *Protocol; > + /// All notifications for this protocol > + LIST_ENTRY Link; > + /// Notification function > + EFI_MM_NOTIFY_FN Function; > + /// Last position notified > + LIST_ENTRY *Position; > +} PROTOCOL_NOTIFY; > + > +// > +// MM Core Global Variables > +// > +extern MM_CORE_PRIVATE_DATA *gMmCorePrivate; > +extern EFI_MM_SYSTEM_TABLE gMmCoreMmst; > +extern LIST_ENTRY gHandleList; > +extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase; > + > +/** > + Called to initialize the memory service. > + > + @param MmramRangeCount Number of MMRAM Regions > + @param MmramRanges Pointer to MMRAM Descriptors > + > +**/ > +VOID > +MmInitializeMemoryServices ( > + IN UINTN MmramRangeCount, > + IN EFI_MMRAM_DESCRIPTOR *MmramRanges > + ); > + > +/** > + The MmInstallConfigurationTable() function is used to maintain the list > + of configuration tables that are stored in the System Management System > + Table. The list is stored as an array of (GUID, Pointer) pairs. The list > + must be allocated from pool memory with PoolType set to EfiRuntimeServicesData. > + > + @param SystemTable A pointer to the MM System Table (SMST). > + @param Guid A pointer to the GUID for the entry to add, update, or remove. > + @param Table A pointer to the buffer of the table to add. > + @param TableSize The size of the table to install. > + > + @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed. > + @retval EFI_INVALID_PARAMETER Guid is not valid. > + @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry. > + @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInstallConfigurationTable ( > + IN CONST EFI_MM_SYSTEM_TABLE *SystemTable, > + IN CONST EFI_GUID *Guid, > + IN VOID *Table, > + IN UINTN TableSize > + ); > + > +/** > + Wrapper function to MmInstallProtocolInterfaceNotify. This is the public API which > + Calls the private one which contains a BOOLEAN parameter for notifications > + > + @param UserHandle The handle to install the protocol handler on, > + or NULL if a new handle is to be allocated > + @param Protocol The protocol to add to the handle > + @param InterfaceType Indicates whether Interface is supplied in > + native form. > + @param Interface The interface for the protocol being added > + > + @return Status code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInstallProtocolInterface ( > + IN OUT EFI_HANDLE *UserHandle, > + IN EFI_GUID *Protocol, > + IN EFI_INTERFACE_TYPE InterfaceType, > + IN VOID *Interface > + ); > + > +/** > + Allocates pages from the memory map. > + > + @param Type The type of allocation to perform > + @param MemoryType The type of memory to turn the allocated pages > + into > + @param NumberOfPages The number of pages to allocate > + @param Memory A pointer to receive the base allocated memory > + address > + > + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. > + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. > + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. > + @retval EFI_SUCCESS Pages successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmAllocatePages ( > + IN EFI_ALLOCATE_TYPE Type, > + IN EFI_MEMORY_TYPE MemoryType, > + IN UINTN NumberOfPages, > + OUT EFI_PHYSICAL_ADDRESS *Memory > + ); > + > +/** > + Allocates pages from the memory map. > + > + @param Type The type of allocation to perform > + @param MemoryType The type of memory to turn the allocated pages > + into > + @param NumberOfPages The number of pages to allocate > + @param Memory A pointer to receive the base allocated memory > + address > + > + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. > + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. > + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. > + @retval EFI_SUCCESS Pages successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalAllocatePages ( > + IN EFI_ALLOCATE_TYPE Type, > + IN EFI_MEMORY_TYPE MemoryType, > + IN UINTN NumberOfPages, > + OUT EFI_PHYSICAL_ADDRESS *Memory > + ); > + > +/** > + Frees previous allocated pages. > + > + @param Memory Base address of memory being freed > + @param NumberOfPages The number of pages to free > + > + @retval EFI_NOT_FOUND Could not find the entry that covers the range > + @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero. > + @return EFI_SUCCESS Pages successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFreePages ( > + IN EFI_PHYSICAL_ADDRESS Memory, > + IN UINTN NumberOfPages > + ); > + > +/** > + Frees previous allocated pages. > + > + @param Memory Base address of memory being freed > + @param NumberOfPages The number of pages to free > + > + @retval EFI_NOT_FOUND Could not find the entry that covers the range > + @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero. > + @return EFI_SUCCESS Pages successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalFreePages ( > + IN EFI_PHYSICAL_ADDRESS Memory, > + IN UINTN NumberOfPages > + ); > + > +/** > + Allocate pool of a particular type. > + > + @param PoolType Type of pool to allocate > + @param Size The amount of pool to allocate > + @param Buffer The address to return a pointer to the allocated > + pool > + > + @retval EFI_INVALID_PARAMETER PoolType not valid > + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. > + @retval EFI_SUCCESS Pool successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmAllocatePool ( > + IN EFI_MEMORY_TYPE PoolType, > + IN UINTN Size, > + OUT VOID **Buffer > + ); > + > +/** > + Allocate pool of a particular type. > + > + @param PoolType Type of pool to allocate > + @param Size The amount of pool to allocate > + @param Buffer The address to return a pointer to the allocated > + pool > + > + @retval EFI_INVALID_PARAMETER PoolType not valid > + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. > + @retval EFI_SUCCESS Pool successfully allocated. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalAllocatePool ( > + IN EFI_MEMORY_TYPE PoolType, > + IN UINTN Size, > + OUT VOID **Buffer > + ); > + > +/** > + Frees pool. > + > + @param Buffer The allocated pool entry to free > + > + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. > + @retval EFI_SUCCESS Pool successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFreePool ( > + IN VOID *Buffer > + ); > + > +/** > + Frees pool. > + > + @param Buffer The allocated pool entry to free > + > + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. > + @retval EFI_SUCCESS Pool successfully freed. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmInternalFreePool ( > + IN VOID *Buffer > + ); > + > +/** > + Installs a protocol interface into the boot services environment. > + > + @param UserHandle The handle to install the protocol handler on, > + or NULL if a new handle is to be allocated > + @param Protocol The protocol to add to the handle > + @param InterfaceType Indicates whether Interface is supplied in > + native form. > + @param Interface The interface for the protocol being added > + @param Notify indicates whether notify the notification list > + for this protocol > + > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate > + @retval EFI_SUCCESS Protocol interface successfully installed > + > +**/ > +EFI_STATUS > +MmInstallProtocolInterfaceNotify ( > + IN OUT EFI_HANDLE *UserHandle, > + IN EFI_GUID *Protocol, > + IN EFI_INTERFACE_TYPE InterfaceType, > + IN VOID *Interface, > + IN BOOLEAN Notify > + ); > + > +/** > + Uninstalls all instances of a protocol:interfacer from a handle. > + If the last protocol interface is remove from the handle, the > + handle is freed. > + > + @param UserHandle The handle to remove the protocol handler from > + @param Protocol The protocol, of protocol:interface, to remove > + @param Interface The interface, of protocol:interface, to remove > + > + @retval EFI_INVALID_PARAMETER Protocol is NULL. > + @retval EFI_SUCCESS Protocol interface successfully uninstalled. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmUninstallProtocolInterface ( > + IN EFI_HANDLE UserHandle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ); > + > +/** > + Queries a handle to determine if it supports a specified protocol. > + > + @param UserHandle The handle being queried. > + @param Protocol The published unique identifier of the protocol. > + @param Interface Supplies the address where a pointer to the > + corresponding Protocol Interface is returned. > + > + @return The requested protocol interface for the handle > + > +**/ > +EFI_STATUS > +EFIAPI > +MmHandleProtocol ( > + IN EFI_HANDLE UserHandle, > + IN EFI_GUID *Protocol, > + OUT VOID **Interface > + ); > + > +/** > + Add a new protocol notification record for the request protocol. > + > + @param Protocol The requested protocol to add the notify > + registration > + @param Function Points to the notification function > + @param Registration Returns the registration record > + > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_SUCCESS Successfully returned the registration record > + that has been added > + > +**/ > +EFI_STATUS > +EFIAPI > +MmRegisterProtocolNotify ( > + IN CONST EFI_GUID *Protocol, > + IN EFI_MM_NOTIFY_FN Function, > + OUT VOID **Registration > + ); > + > +/** > + Locates the requested handle(s) and returns them in Buffer. > + > + @param SearchType The type of search to perform to locate the > + handles > + @param Protocol The protocol to search for > + @param SearchKey Dependant on SearchType > + @param BufferSize On input the size of Buffer. On output the > + size of data returned. > + @param Buffer The buffer to return the results in > + > + @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is > + returned in BufferSize. > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_SUCCESS Successfully found the requested handle(s) and > + returns them in Buffer. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLocateHandle ( > + IN EFI_LOCATE_SEARCH_TYPE SearchType, > + IN EFI_GUID *Protocol OPTIONAL, > + IN VOID *SearchKey OPTIONAL, > + IN OUT UINTN *BufferSize, > + OUT EFI_HANDLE *Buffer > + ); > + > +/** > + Return the first Protocol Interface that matches the Protocol GUID. If > + Registration is pasased in return a Protocol Instance that was just add > + to the system. If Retistration is NULL return the first Protocol Interface > + you find. > + > + @param Protocol The protocol to search for > + @param Registration Optional Registration Key returned from > + RegisterProtocolNotify() > + @param Interface Return the Protocol interface (instance). > + > + @retval EFI_SUCCESS If a valid Interface is returned > + @retval EFI_INVALID_PARAMETER Invalid parameter > + @retval EFI_NOT_FOUND Protocol interface not found > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLocateProtocol ( > + IN EFI_GUID *Protocol, > + IN VOID *Registration OPTIONAL, > + OUT VOID **Interface > + ); > + > +/** > + Manage MMI of a particular type. > + > + @param HandlerType Points to the handler type or NULL for root MMI handlers. > + @param Context Points to an optional context buffer. > + @param CommBuffer Points to the optional communication buffer. > + @param CommBufferSize Points to the size of the optional communication buffer. > + > + @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced. > + @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced. > + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced. > + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiManage ( > + IN CONST EFI_GUID *HandlerType, > + IN CONST VOID *Context OPTIONAL, > + IN OUT VOID *CommBuffer OPTIONAL, > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + Registers a handler to execute within MM. > + > + @param Handler Handler service funtion pointer. > + @param HandlerType Points to the handler type or NULL for root MMI handlers. > + @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function. > + > + @retval EFI_SUCCESS Handler register success. > + @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiHandlerRegister ( > + IN EFI_MM_HANDLER_ENTRY_POINT Handler, > + IN CONST EFI_GUID *HandlerType OPTIONAL, > + OUT EFI_HANDLE *DispatchHandle > + ); > + > +/** > + Unregister a handler in MM. > + > + @param DispatchHandle The handle that was specified when the handler was registered. > + > + @retval EFI_SUCCESS Handler function was successfully unregistered. > + @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle. > + > +**/ > +EFI_STATUS > +EFIAPI > +MmiHandlerUnRegister ( > + IN EFI_HANDLE DispatchHandle > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmDriverDispatchHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmFvDispatchHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmLegacyBootHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmExitBootServiceHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmReadyToBootHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmReadyToLockHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + This function is the main entry point for an MM handler dispatch > + or communicate-based callback. > + > + @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister(). > + @param Context Points to an optional handler context which was specified when the handler was registered. > + @param CommBuffer A pointer to a collection of data in memory that will > + be conveyed from a non-MM environment into an MM environment. > + @param CommBufferSize The size of the CommBuffer. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +MmEndOfDxeHandler ( > + IN EFI_HANDLE DispatchHandle, > + IN CONST VOID *Context, OPTIONAL > + IN OUT VOID *CommBuffer, OPTIONAL > + IN OUT UINTN *CommBufferSize OPTIONAL > + ); > + > +/** > + Place holder function until all the MM System Table Service are available. > + > + @param Arg1 Undefined > + @param Arg2 Undefined > + @param Arg3 Undefined > + @param Arg4 Undefined > + @param Arg5 Undefined > + > + @return EFI_NOT_AVAILABLE_YET > + > +**/ > +EFI_STATUS > +EFIAPI > +MmEfiNotAvailableYetArg5 ( > + UINTN Arg1, > + UINTN Arg2, > + UINTN Arg3, > + UINTN Arg4, > + UINTN Arg5 > + ); > + > +// > +//Functions used during debug buils > +// > + > +/** > + Traverse the discovered list for any drivers that were discovered but not loaded > + because the dependency expressions evaluated to false. > + > +**/ > +VOID > +MmDisplayDiscoveredNotDispatched ( > + VOID > + ); > + > +/** > + Add free MMRAM region for use by memory service. > + > + @param MemBase Base address of memory region. > + @param MemLength Length of the memory region. > + @param Type Memory type. > + @param Attributes Memory region state. > + > +**/ > +VOID > +MmAddMemoryRegion ( > + IN EFI_PHYSICAL_ADDRESS MemBase, > + IN UINT64 MemLength, > + IN EFI_MEMORY_TYPE Type, > + IN UINT64 Attributes > + ); > + > +/** > + Finds the protocol entry for the requested protocol. > + > + @param Protocol The ID of the protocol > + @param Create Create a new entry if not found > + > + @return Protocol entry > + > +**/ > +PROTOCOL_ENTRY * > +MmFindProtocolEntry ( > + IN EFI_GUID *Protocol, > + IN BOOLEAN Create > + ); > + > +/** > + Signal event for every protocol in protocol entry. > + > + @param Prot Protocol interface > + > +**/ > +VOID > +MmNotifyProtocol ( > + IN PROTOCOL_INTERFACE *Prot > + ); > + > +/** > + Finds the protocol instance for the requested handle and protocol. > + Note: This function doesn't do parameters checking, it's caller's responsibility > + to pass in valid parameters. > + > + @param Handle The handle to search the protocol on > + @param Protocol GUID of the protocol > + @param Interface The interface for the protocol being searched > + > + @return Protocol instance (NULL: Not found) > + > +**/ > +PROTOCOL_INTERFACE * > +MmFindProtocolInterface ( > + IN IHANDLE *Handle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ); > + > +/** > + Removes Protocol from the protocol list (but not the handle list). > + > + @param Handle The handle to remove protocol on. > + @param Protocol GUID of the protocol to be moved > + @param Interface The interface of the protocol > + > + @return Protocol Entry > + > +**/ > +PROTOCOL_INTERFACE * > +MmRemoveInterfaceFromProtocol ( > + IN IHANDLE *Handle, > + IN EFI_GUID *Protocol, > + IN VOID *Interface > + ); > + > +/** > + This is the POSTFIX version of the dependency evaluator. This code does > + not need to handle Before or After, as it is not valid to call this > + routine in this case. POSTFIX means all the math is done on top of the stack. > + > + @param DriverEntry DriverEntry element to update. > + > + @retval TRUE If driver is ready to run. > + @retval FALSE If driver is not ready to run or some fatal error > + was found. > + > +**/ > +BOOLEAN > +MmIsSchedulable ( > + IN EFI_MM_DRIVER_ENTRY *DriverEntry > + ); > + > +/** > + Dump MMRAM information. > + > +**/ > +VOID > +DumpMmramInfo ( > + VOID > + ); > + > +extern UINTN mMmramRangeCount; > +extern EFI_MMRAM_DESCRIPTOR *mMmramRanges; > +extern EFI_SYSTEM_TABLE *mEfiSystemTable; > + > +#endif > diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.inf b/StandaloneMmPkg/Core/StandaloneMmCore.inf > new file mode 100644 > index 0000000000..c5eaa14ba3 > --- /dev/null > +++ b/StandaloneMmPkg/Core/StandaloneMmCore.inf > @@ -0,0 +1,80 @@ > +## @file > +# This module provide an SMM CIS compliant implementation of SMM Core. > +# > +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
> +# Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001A > + BASE_NAME = StandaloneMmCore > + FILE_GUID = 6E14B6FD-3600-4DD6-A17A-206B3B6DCE16 > + MODULE_TYPE = MM_CORE_STANDALONE > + VERSION_STRING = 1.0 > + PI_SPECIFICATION_VERSION = 0x00010032 > + ENTRY_POINT = StandaloneMmMain > + > +# VALID_ARCHITECTURES = IA32 X64 AARCH64 > + > +[Sources] > + StandaloneMmCore.c > + StandaloneMmCore.h > + StandaloneMmCorePrivateData.h > + Page.c > + Pool.c > + Handle.c > + Locate.c > + Notify.c > + Dependency.c > + Dispatcher.c > + Mmi.c > + InstallConfigurationTable.c > + FwVol.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + StandaloneMmPkg/StandaloneMmPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + CacheMaintenanceLib > + DebugLib > + FvLib > + HobLib > + MemoryAllocationLib > + MemLib > + PeCoffLib > + ReportStatusCodeLib > + StandaloneMmCoreEntryPoint > + > +[Protocols] > + gEfiDxeMmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister > + gEfiMmReadyToLockProtocolGuid ## PRODUCES > + gEfiMmEndOfDxeProtocolGuid ## PRODUCES > + gEfiLoadedImageProtocolGuid ## PRODUCES > + gEfiMmConfigurationProtocolGuid ## CONSUMES > + > +[Guids] > + gAprioriGuid ## SOMETIMES_CONSUMES ## File > + gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister > + gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister > + ## SOMETIMES_CONSUMES ## GUID # Locate protocol > + ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister > + gEdkiiMemoryProfileGuid > + gZeroGuid ## SOMETIMES_CONSUMES ## GUID > + gEfiHobListGuid > + gMmCoreDataHobGuid > + gMmFvDispatchGuid > + gEfiEventLegacyBootGuid > + gEfiEventExitBootServicesGuid > + gEfiEventReadyToBootGuid > diff --git a/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h > new file mode 100644 > index 0000000000..faedf3ff2d > --- /dev/null > +++ b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h > @@ -0,0 +1,66 @@ > +/** @file > + The internal header file that declared a data structure that is shared > + between the MM IPL and the MM Core. > + > + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef _STANDALONE_MM_CORE_PRIVATE_DATA_H_ > +#define _STANDALONE_MM_CORE_PRIVATE_DATA_H_ > + > +#include > + > +// > +// Page management > +// > + > +typedef struct { > + LIST_ENTRY Link; > + UINTN NumberOfPages; > +} FREE_PAGE_LIST; > + > +extern LIST_ENTRY mMmMemoryMap; > + > +// > +// Pool management > +// > + > +// > +// MIN_POOL_SHIFT must not be less than 5 > +// > +#define MIN_POOL_SHIFT 6 > +#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT) > + > +// > +// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1 > +// > +#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1) > +#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT) > + > +// > +// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes > +// > +#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1) > + > +typedef struct { > + UINTN Size; > + BOOLEAN Available; > +} POOL_HEADER; > + > +typedef struct { > + POOL_HEADER Header; > + LIST_ENTRY Link; > +} FREE_POOL_HEADER; > + > +extern LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX]; > + > +#endif > diff --git a/StandaloneMmPkg/Include/Guid/MmFvDispatch.h b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h > new file mode 100644 > index 0000000000..fb194d3474 > --- /dev/null > +++ b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h > @@ -0,0 +1,38 @@ > +/** @file > + GUIDs for MM Event. > + > +Copyright (c) 2015, Intel Corporation. All rights reserved.
> +Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + > +This program and the accompanying materials are licensed and made available under > +the terms and conditions of the BSD License that accompanies this distribution. > +The full text of the license may be found at > +http://opensource.org/licenses/bsd-license.php. > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef __MM_FV_DISPATCH_H__ > +#define __MM_FV_DISPATCH_H__ > + > +#define MM_FV_DISPATCH_GUID \ > + { 0xb65694cc, 0x9e3, 0x4c3b, { 0xb5, 0xcd, 0x5, 0xf4, 0x4d, 0x3c, 0xdb, 0xff }} > + > +extern EFI_GUID gMmFvDispatchGuid; > + > +#pragma pack(1) > +typedef struct { > + EFI_PHYSICAL_ADDRESS Address; > + UINT64 Size; > +} EFI_MM_COMMUNICATE_FV_DISPATCH_DATA; > + > +typedef struct { > + EFI_GUID HeaderGuid; > + UINTN MessageLength; > + EFI_MM_COMMUNICATE_FV_DISPATCH_DATA Data; > +} EFI_MM_COMMUNICATE_FV_DISPATCH; > +#pragma pack() > + > +#endif > diff --git a/StandaloneMmPkg/Include/StandaloneMm.h b/StandaloneMmPkg/Include/StandaloneMm.h > new file mode 100644 > index 0000000000..0e420315bb > --- /dev/null > +++ b/StandaloneMmPkg/Include/StandaloneMm.h > @@ -0,0 +1,36 @@ > +/** @file > + Standalone MM. > + > +Copyright (c) 2015, Intel Corporation. All rights reserved.
> +Copyright (c) 2016 - 2017, ARM Limited. All rights reserved.
> + > +This program and the accompanying materials > +are licensed and made available under the terms and conditions > +of the BSD License which accompanies this distribution. The > +full text of the license may be found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef _STANDALONE_MM_H_ > +#define _STANDALONE_MM_H_ > + > +#include > + > +typedef > +EFI_STATUS > +(EFIAPI *MM_IMAGE_ENTRY_POINT) ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_MM_SYSTEM_TABLE *MmSystemTable > + ); > + > +typedef > +EFI_STATUS > +(EFIAPI *STANDALONE_MM_FOUNDATION_ENTRY_POINT) ( > + IN VOID *HobStart > + ); > + > +#endif > -- > 2.16.2 >