From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=40.107.0.53; helo=eur02-am5-obe.outbound.protection.outlook.com; envelope-from=achin.gupta@arm.com; receiver=edk2-devel@lists.01.org Received: from EUR02-AM5-obe.outbound.protection.outlook.com (mail-eopbgr00053.outbound.protection.outlook.com [40.107.0.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 45064203B9257 for ; Mon, 30 Apr 2018 13:16:37 -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=xR7USNwJQBtIkvhtJY6ePsMKf+KOo6vud4lXS/Cew+U=; b=N7VAC+tVsM6I3QSTg+XTwQuw/aDt61SRSC0soLO1CjUCri+BP/+mFDRQ/G8RufJXZVuuMXYvSwDUPWRYJHWzL4JKUolPhDAi8gRS8kPTxTJlb/WI1dZRc7bnoead5MNHjiWaXzck6lMTADeOPBix0G8vlNrC6lUKgElYnqoAc6g= 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 20:16:27 +0000 Date: Mon, 30 Apr 2018 21:17:55 +0100 From: Achin Gupta To: Ard Biesheuvel Cc: Laszlo Ersek , "Kinney, Michael D" , Leif Lindholm , Andrew Fish , Supreeth Venkatesh , "edk2-devel@lists.01.org" , "Gao, Liming" , "Yao, Jiewen" , nd Message-ID: <20180430201753.GC663@e104320-lin> References: <20180406144223.10931-1-supreeth.venkatesh@arm.com> <20180406144223.10931-14-supreeth.venkatesh@arm.com> <20180430191942.GX663@e104320-lin> MIME-Version: 1.0 In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-Originating-IP: [217.140.96.140] X-ClientProxiedBy: CWLP265CA0045.GBRP265.PROD.OUTLOOK.COM (2603:10a6:401:11::33) 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)(4534165)(4627221)(201703031133081)(201702281549075)(2017052603328)(7153060)(7193020); SRVR:VI1PR08MB2991; X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 3:xrR+AtsPFguFIeDxvXbKiU6sMtEJifbei/Rqc3YdIN5JFUQkdeZ3vSMvbdaX9/OTSLkAeSaLARP81ic4Q/MMONt5VukMF882zkDAZn6Qfzu6eUjFB6F2GjatxSzagegRzCvS9UMbwVrWb8Gcb807JSN8kSayjGcZ5MSfdVDjTsn0Df4VV/bGnmNw63IpiqXHA3bKQp8c+rR0+5Vq1gY+zMEPaP/rLUkITgqAo7CNkCKWLVA/WeZydyXtPRY+l5Tt; 25:M+eOGGadtldcqygI9vTjjooUMI5goA4fYVM9DXmGKsohCYf3aHJD83Zkk8WYM0zeaTBPlxVaNQDGYnZCV5ovdz/NqUUl1sNXQihOruCZ8dhaMiVE+RuXLLmmi/sk6bZRj37nWySieZrfckfV2dnQNoeLtVGdLOsiql0gB0Xi74iuyEATl2K8BJy8mDcwUyxCk3kGDwQ3QXpUyy/1rF8SURepkW1i2ZW62B+j8V3PCxVQSAQzJ5cPbwlz6qhoZ6/HRwKhIUPv8EY8gEeJTDcKhM+ycqHQF+9lIX40fMfdeQZjjPJQyPDVp//8AeCcu46fDRpm/gk1CjdTKyipu+qJZg==; 31:m2uKWGbry5avLo8P2nZD0bK5F5zmr/XOF6HKiX5ts3hXyWRhcmJy0RKUdsie3M2/63cPDMgeK85jaYd8I/vOwW/Sb1Si/7q4stBpft8qMq8KIRWiRUOnRX5oUT5WinEwmHNEfCyqPysPN9DOfMZ3rntRh9wSaIZ/fd8Y3/K6AwnswR2CS2BZGlt/3gCgS0OaQaXUqh8v3rbJy8mliYqffgQQlntMWiz9ENgn+HeIF+E= X-MS-TrafficTypeDiagnostic: VI1PR08MB2991: NoDisclaimer: True X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 20:N62vizeQa+LgMI51zWn9rkR8/B99vO/HJyZ6SnxqIGEFGIYzX10yI27eZLJVMZ5d1JFTXYP+NXC79tijFwJ+4f2EC46O3LhlBOy1/Ep4Dn9tG7lbiLHzTcvWuNwlDlCcAWwCScWORQmRc5/lFHUJX8qpeeGMx5NLX1a4Et6QXSrBGkOpe3TuiAoZpaGBJ9bZsQYqyV3FnHO55Gti8EqEvgaOKfeytYAvzCNHnmEeVhLXm3zADzOPqQqpEFTv0qc/; 4:ST1Jb7yyun4A9L6Ws8Va2rmebpqAkwGCWOLluPNFx5PM01wXFcI7WJIL78nxM1nZxB7y4JiLnLQo3wTbz3xoM8A1F2Esb5ARq8AXkmGNXwjSCMkY+uMNttM20Wq8n6X4wVweu77Hoed18J1x+dphGkbo8LPTwWZMLhWrqdR+W4VQlG0tO158zaKm28IV4ksUs2u+jw0RF7AJ5/U2YBWMslaHBC8eiAjz00C2Qb099GgRiPfuIgothJusSd3yxTkDkp4Zx+Hmm0zESwFQOfKdCP25VEhi71kF8hI3dzp9xXlsnGu6VhlESSezyNh8PrKg28uGC/yHEAcbJQ4zPXxrwpB/bC3fty2hWJypBJElORo= 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)(3002001)(3231254)(944501410)(52105095)(93006095)(93001095)(10201501046)(6055026)(6041310)(20161123562045)(20161123560045)(20161123558120)(20161123564045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(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)(366004)(396003)(376002)(50944005)(199004)(189003)(51914003)(476003)(11346002)(956004)(229853002)(6916009)(76176011)(6116002)(3846002)(66066001)(6496006)(23726003)(446003)(52116002)(1076002)(72206003)(93886005)(47776003)(966005)(6666003)(5660300001)(316002)(33716001)(54906003)(26005)(86362001)(478600001)(16586007)(97736004)(58126008)(81156014)(81166006)(8676002)(8936002)(8666007)(68736007)(16200700003)(53946003)(25786009)(6246003)(53936002)(9686003)(33656002)(486006)(6306002)(53376002)(55016002)(44832011)(53546011)(386003)(15188155005)(2906002)(33896004)(16799955002)(50466002)(305945005)(59450400001)(105586002)(106356001)(186003)(16526019)(7736002)(4326008)(18370500001)(107986001)(579004)(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:Yu87OrKHNweMsWqSiVip7SuJbzG24eGZJlREPyMyt?= =?us-ascii?Q?78KZP70JMRSw1pX/+k+UqN5izYlw9N8WvaOzWqr2nt71fT5avJXbbjKZL5vp?= =?us-ascii?Q?xv0UxKCHv4SZq9E7RhM/m0RM7yie0CoPBf6Bc7Vja8UZZXlHcNW2Lr+obRVh?= =?us-ascii?Q?37eg64T1W1lFoTLBzrI5p3kn3ZtByzAAezxQh19dAhgai2y0jH4/mnG+oKcT?= =?us-ascii?Q?n3AOaePSlLeHIc3PmGUpge0RXkShxYSTiMT/k05f1EJmLVe47m9w/oGWguWO?= =?us-ascii?Q?w8vDfrZ5eKIW/wYBCFQ95w+uTGdO3O1AUN2OMd8vkrjGbJpPI6vVqYddfNkw?= =?us-ascii?Q?ut5mKgEJ5esliQqE6p6cH6qPEJmEebd0ge/LrWpELwZXhRL7WeCHcfhlhdjq?= =?us-ascii?Q?tGj+fJQuJc49GMAvQks1H27A4ve5mj3rzJR4ICZKWCntgWL20Cu4uEKtYotU?= =?us-ascii?Q?bxaqI+unZY6BK1xTjfP37lcwjIUqCRA5/qDkvaRheYJVqeyX7RwaR0FyE4Nh?= =?us-ascii?Q?6zu4G6SS8nC1CNCRFGBRCHrDBPeAeoXZP8L7AJdpeDf67PcQHKo26RzcypIl?= =?us-ascii?Q?GneEM4ZX1V2q4idxoKkrWpUIGnxMbZvvxCmXCe9kvDUujWW7wQunkONM8c6g?= =?us-ascii?Q?J3UAkjwBwUtEZMaw08kLKoNTKU15cBimql+x3AvEpPVqfR4yj2WCplMXCemc?= =?us-ascii?Q?kv4+m/IMVaY5u/JD2LcM4gaBLydQ8Zw0ihrbBeqbP9ANeqCkdCrlzRRfSeLg?= =?us-ascii?Q?dZQGosiQRfQ/JOnnz8Ua4Ykb8CZcIWSY7V9xuaz3C57QuSQNdm+ScZPVfF/9?= =?us-ascii?Q?9nL9vzqwWJYEP5WUDVQ4Iyk4XA9V8ABGYhKUQl5B/6sMvcYWWsRmuA7vLpDR?= =?us-ascii?Q?HsC+yWTekbn7Bd6MEHTN3e9/lJTxo4pugg3Yn1C9+wfGCRb45KRQ6I7QSAFx?= =?us-ascii?Q?/UXuPDazA3YKD0XGmv8pE4jWCCy1vMIcF7bQHshDprQXOi2DKcxpTRcNSdQB?= =?us-ascii?Q?5/arhUHYFW9k76EBf5adOT7hMnnFDBZhAeYVNNUUAQnbA8oyYi+MHkz8ZxNU?= =?us-ascii?Q?mTrP7mYtwBMY5N6svo3pg1v1y21lGzRdDSDjkc/Idq41ljpJNkOjbW+l+b7q?= =?us-ascii?Q?YvV9+jSc7NFmM/rmGU5nwT2GR8ectr9j63puPMgwQ4fv8lN4Y6podKlcggEU?= =?us-ascii?Q?ZlEDnSQfvWru26JV8HlL8GM1QCF4PwaEsaJOVNYvD1ZcmO9XhWSH65Q4YkFr?= =?us-ascii?Q?j83aSoXveTvcxkaOaYgLLeqcZ1+Zvcieq3X+Dm+3sZKyuNKyWcET72ruCzOQ?= =?us-ascii?Q?v3B/UjgXni+tCo2ZB2Y9I1vA6LrRU3XyI9dYmZM0za4GmPyAmVHRTV40Wv7C?= =?us-ascii?Q?43uEtbAjxpEWgJJTq3afO1B1uhOfNBJen8zmQwbR0n0F1Ju1Rw7ABx/HrMbd?= =?us-ascii?Q?ZVV9jWb8wpeAFAxtHzEjRE7Cwzz+dOGZVw4JQx+oHWzwL+Oy50REUbAmKb0M?= =?us-ascii?Q?UgKA61aXd12HcxisC3k410yz+uyR8fV6MgrjDq5bv7+Xd62ONH1zBR+taErQ?= =?us-ascii?Q?fUZlNyzMnABvYG8zJrHwIOSJll0jjro0AD37vt7dvfWUHA+z0aQH3m/vfLIM?= =?us-ascii?Q?bvjsSNs2K6OAV8PnURMUGrCaN6NIN6eBeILzUhpx3LPGSONMcTTV891yXbwD?= =?us-ascii?Q?PRIc/qiaenjoRHXwzcnTyz9amjCnSu/eX98IonnRQc1ITA=3D?= X-Microsoft-Antispam-Message-Info: jh+8Au0blLZe3VC+tqYvl3sr7WklRnvtsoAH/ShppJdeibNbDeLaPNkG2SmDPPBFJMvwgiSo4yjQA/elECCehN7TMCeziRjHnZUJ0p1esIBZpR16q8TO0n2ZnUTX4WUGzHIzn7+DSAcMw61NVnKT5AU7wCNGVrmLjkQM/DIVvTSIY4Yr9/Jm4GFhZ+z6E1J3 X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 6:Ckg5+f17XbRRUmSJknLoNsnn5um6n+C3mUUixdjc1neO7AZ/UHEQxyrKeJUC0TKQtNVzvSmpwwWPFE94YPRHwh43L2ZWxd6eRS+4NYSbbeX112xabyD1uFVIrN+gnNrm8IqeOvjdUUTO10aJfu6T7o0UDIXu3jl2JZ0R58gz9yI8NJXiRVBlQxHB4cOKksX4aEa4ykUsljSV/LcTZpQjlmgNIzk4+wnxd3+wNqM7Q4YjhSUCICHEIA5gnHzChGbxyWyK/7JuNAWifagngyw1umNwlofqM//IfX37X2lyKdQqipuG7Cp6SVFHFPqQxm6TOnRREuvCC2U85Q/1xGxF9i+JP3IM54iNpmjlZV9aWuzJUaKte33CzNJexuY6CzZM/Yd7h3+wTls7etEnK//9wJWnXdp4IbH3t8wxQ3/vPEVIbvX0BdkQY329NgdXoIAz9q87BEBtZfk9nFrW0uZ1ow==; 5:jWf1OOshvUu+iyIZkL5OrDmNljAfufWYa4OOlVFNvTxoucC+g3xlsAiTt7z8Bwe+JNBkhF4GqAhsKRO6VOvmaYIylT1/3KbN6HBUl01gjLtuygKe44D4xjK7SRk7VxID2asz+PYfTbcxYvoM+9GarWGdIJMn6qqq+gADwMzSKRA=; 24:EPlLLr/MHdjPll7oJkLtVfq6kh7+5rNtF5S2VhBaWLy6dAvLLC4gZv6nVSIIIxjGJtoqU/98t+MAW4lxwD9ZF5BLWctg6wOQxHGpguJa1zM= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; VI1PR08MB2991; 7:kxDuSMOjtWGIqG1XSLg8gYvQWuJskF2sw/ZLXMfXLgzJD1ceoOJsUYcFO/diOvpKV9YOhsgcF8lmflBxtdf6aBAbjL5soDWNE5MxJW8y3MjlxuJzyRjSd2WbWu/pYnbz3fQAgmPyxkfnyT/vljBeElI4EQkp95aeudlbA/MSsUc6MLQrKDEJ3KliLP1Af0OG6gKMDAS2Wjo09OGYjcPHQOUP1V4T9smOmLRPDAubDSelxJEmSYvQWAQQgxQ/QOev X-MS-Office365-Filtering-Correlation-Id: cf30c24d-7cbe-4b70-ea9d-08d5aed74123 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2018 20:16:27.1867 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: cf30c24d-7cbe-4b70-ea9d-08d5aed74123 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 20:16:39 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Mon, Apr 30, 2018 at 09:28:57PM +0200, Ard Biesheuvel wrote: > On 30 April 2018 at 21:19, Achin Gupta wrote: > > 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. > > I disagree. A signoff does not assert authorship, it only means that > the contributor asserts that the license permits him to contribute > this code under the tianocore contribution agreement. Adding a signoff > on behalf of someone else should be avoided in my opinion, because it > suggests that code can only be contributed by the original author. > Also, even if the author made the code available under a compatible > license, it does not mean he subscribes to the Tianocore contribution > agreement, and adding a signoff on behalf of someone else does imply > that (although this should not be a problem in this particular case) > > Anyone can contribute code that is available under a compatible > license, and it is not generally possible to decide who should be > credited as authors for code that originates in other projects. > > If you want to credit the author, you can do that in the commit log. Thanks for the clarification. I am fine with that. cheers, Achin > > > > > 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 > >>