From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail03.groups.io (mail03.groups.io [45.79.227.220]) by spool.mail.gandi.net (Postfix) with ESMTPS id A5C11AC0D77 for ; Fri, 12 Apr 2024 14:34:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=yrRcur/ugrdl6zBNGxuVtvjcQRfmKqmc3Kpa7A6FQzQ=; c=relaxed/simple; d=groups.io; h=Received-SPF:Received-SPF:From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:NoDisclaimer:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type; s=20240206; t=1712932452; v=1; b=GLsPVSfGw+wB2fxXbJEHp7gOYJIdPZRXPeBi/vdSGzqeBsA6vWzN81wFKW3+XesO6+UPId9y lwTTP/PUC14I328VVwPXf5E7dPv+W6Mq8WfjkAEnXKlMlz7p/r0SwR/y/GpMna8fGFaKvqUXqPT 2QilxFgX0aDY7hh9r3ZkE3UH3L+9S7SzJ3C7JlGedVN2AHOzvt5XB4lJuK9BAbgdBNl71PSCRDY D+WnbgQ47xqOQTQY3VwxhZnF6avswEuko2UeuPB7ig1GBr51bTS6MMF+VyFU24dGMU26+hK2DOB 81gGZMDtaBl3RPG7mlO907Ef3qSO0KqPzFUE2WH++0DyA== X-Received: by 127.0.0.2 with SMTP id fwctYY7687511xf5erB4jXG1; Fri, 12 Apr 2024 07:34:12 -0700 X-Received: from EUR04-VI1-obe.outbound.protection.outlook.com (EUR04-VI1-obe.outbound.protection.outlook.com [40.107.8.74]) by mx.groups.io with SMTP id smtpd.web11.47969.1712932443454253788 for ; Fri, 12 Apr 2024 07:34:04 -0700 X-Received: from DU2PR04CA0044.eurprd04.prod.outlook.com (2603:10a6:10:234::19) by AS2PR08MB10352.eurprd08.prod.outlook.com (2603:10a6:20b:578::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.46; Fri, 12 Apr 2024 14:33:59 +0000 X-Received: from DU2PEPF0001E9C1.eurprd03.prod.outlook.com (2603:10a6:10:234:cafe::30) by DU2PR04CA0044.outlook.office365.com (2603:10a6:10:234::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7452.27 via Frontend Transport; Fri, 12 Apr 2024 14:33:59 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C X-Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by DU2PEPF0001E9C1.mail.protection.outlook.com (10.167.8.70) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.7452.22 via Frontend Transport; Fri, 12 Apr 2024 14:33:59 +0000 X-Received: ("Tessian outbound 01a47eb2eb85:v313"); Fri, 12 Apr 2024 14:33:59 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 9b1c9290148f2281 X-CR-MTA-TID: 64aa7808 X-Received: from 63a467efbbcf.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 690DF3B2-4CDC-4DCB-960F-B09C7A5EE600.1; Fri, 12 Apr 2024 14:33:47 +0000 X-Received: from EUR01-VE1-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 63a467efbbcf.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Fri, 12 Apr 2024 14:33:47 +0000 X-Received: from DUZPR01CA0003.eurprd01.prod.exchangelabs.com (2603:10a6:10:3c3::15) by DU0PR08MB8423.eurprd08.prod.outlook.com (2603:10a6:10:405::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.55; Fri, 12 Apr 2024 14:33:41 +0000 X-Received: from DU2PEPF00028D01.eurprd03.prod.outlook.com (2603:10a6:10:3c3:cafe::49) by DUZPR01CA0003.outlook.office365.com (2603:10a6:10:3c3::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7472.26 via Frontend Transport; Fri, 12 Apr 2024 14:33:41 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 40.67.248.234) smtp.mailfrom=arm.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 40.67.248.234 as permitted sender) receiver=protection.outlook.com; client-ip=40.67.248.234; helo=nebula.arm.com; pr=C X-Received: from nebula.arm.com (40.67.248.234) by DU2PEPF00028D01.mail.protection.outlook.com (10.167.242.185) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.7452.22 via Frontend Transport; Fri, 12 Apr 2024 14:33:41 +0000 X-Received: from AZ-NEU-EX04.Arm.com (10.251.24.32) by AZ-NEU-EX03.Arm.com (10.251.24.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 12 Apr 2024 14:33:37 +0000 X-Received: from E114225.Arm.com (10.1.196.56) by mail.arm.com (10.251.24.32) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 12 Apr 2024 14:33:36 +0000 From: "Sami Mujawar" To: CC: Sami Mujawar , , , , , , , Subject: [edk2-devel] [PATCH v2 25/45] ArmVirtPkg: Introduce Realm Aperture Management Protocol Date: Fri, 12 Apr 2024 15:33:02 +0100 Message-ID: <20240412143322.5244-26-sami.mujawar@arm.com> In-Reply-To: <20240412143322.5244-1-sami.mujawar@arm.com> References: <20240412143322.5244-1-sami.mujawar@arm.com> MIME-Version: 1.0 X-EOPAttributedMessage: 1 X-MS-TrafficTypeDiagnostic: DU2PEPF00028D01:EE_|DU0PR08MB8423:EE_|DU2PEPF0001E9C1:EE_|AS2PR08MB10352:EE_ X-MS-Office365-Filtering-Correlation-Id: a54bd0ed-674d-43cf-1c2e-08dc5afd9770 x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: 3CNKM0QGkw5GpalmbSvTC53Tpv73zKJpEeOgfmuWhbJq8CHCxTuQyq7KNwYJfE74KBqhUKqB7QOl9ZvAeXOL86pzZkt7XPkxBZUY4hxsSTIqrRPSks75N2HJYxWE9Fwt+XPYSkqAKVAqkhAgRmTw9OY5E7Ag4puhSDrOUVcVAKTiJ6utENbagPzYQhNWLS8PrtQhDeMiKjpKHBUkTdzZ8neBXOT+aPRIKSOUo1B2c47vdhc0zpuyky2vlXYy/Cyx7mvaUzuu65V8dmGAI6fCVjfqqrbH/c1vqM1uM3HG8MHH1JJtCcVm9QGGTREp10hz1i860BK+zAw8sT/lsfwFdHyOx0iykajtmyMhO7p5lFc8OvGLPerE9Pe3yNUKK0ZnARaC5VU6bLllCMOgIqRuwNapzNql4Wz5tW/zR8+jyWPiVku2amLLmVOvLJ+cixidEkP8srYlz//fdmT1h6RCNGZLnW3DyEP67FrDfjPS/B4mC9fu2YhKuvsQOe4KP0t55AO5smR65JRZFphq2bLlodpKaQIA4o2FVE/ze8nNSjaAngF1osiA1Gmfg82yNDzXtCly4rnkc52rANarAgwIXkmGIl40FROUFl/d4I0d9/JnsSZcT+1kG8ajI5TxuRHszFlT/a6aeoOtTlNNfsVXUhqbhdng1a3XnA7XMr5RuCRqGjc7VHKdBLQ4H1SmbCP+bSsppZzFFeYOyfdUqn+aAQTD+sxHireDH5p1/dyuLUwzCM6raJdq3hDycdcUeAQT X-Forefront-Antispam-Report-Untrusted: CIP:40.67.248.234;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:nebula.arm.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(82310400014)(376005)(1800799015)(36860700004);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: DU0PR08MB8423 X-MS-Exchange-Transport-CrossTenantHeadersStripped: DU2PEPF0001E9C1.eurprd03.prod.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: fd20873b-971a-4f7b-cae2-08dc5afd8cf2 X-Microsoft-Antispam-Message-Info: XjpXLBTC9KaqMrSadyawqrLmN0U5tuiOps41QzAoMpXBBqHuASWi7byAvKjQqvrwO9PfZlaHV+mCSEJ9qWjNjm6yajcvxbiz96d2X9AIohR0lzwolo89hNwybuECDJjA216ZTRh8cVNHhDZVRR6s5tvl6XjTBFXiIkjYU3mHpQfpwXfHBU0zVRfn8Mca2j0QGALjBYFw8MfO62UVOmXPHa9SXD8B/SB+mMfweL+BbajlMBuo7eJ+qD60axJ6MjUedGdS1cjgcrA5b6anvBSffojbXOBBn6jFBQ1Mm9rixaDbc/S3yflTYo/h+34XM7Vaml+6Eip/oVjkgk19IU8zwaghw/4Y9Ctccfyh9GASW0JAPdsFVPyXSI6w4OBAUDxE3LgUfx3RQBFV7NfLvp443leSQhNCaGR8FD+1sDDPEORWjkuRdhusLCxFaSisbAWD5BIK4hm+0pdhskWzpY6m1gRdvVMgNCQg32Mhx/c8X9RBQLNQ4tAF2S5ctw0Al42fusmsQz8esa4aoeOZ2GBPzKGUbpmI3yTVYiMqfqwusmYNIy13kWvYQZncXj7LHk0LvK/hINwQdMnHDDrEG6NrGo73vav01kOI64s8L9lUQCqAZgUeITv0ZPks5pXwXkIJp3TbAgn6UF1Y6WNojnO8X3uuORIpjTpmlKhjEZ3mKilWChLjpyhcum6Ee/zHdGoVowrINe6xByokWt+CyGv0y8eoOTDoWMgbZLG9ga2rDztiZyWwMHb9w9LocRvLlRfj X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Apr 2024 14:33:59.3544 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: a54bd0ed-674d-43cf-1c2e-08dc5afd9770 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: DU2PEPF0001E9C1.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS2PR08MB10352 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Fri, 12 Apr 2024 07:34:04 -0700 Resent-From: sami.mujawar@arm.com Reply-To: devel@edk2.groups.io,sami.mujawar@arm.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: KRuIaHk6fx5u3bX5UYrBwttlx7686176AA= Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=GLsPVSfG; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=arm.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.227.220 as permitted sender) smtp.mailfrom=bounce@groups.io The Realm Aperture Management Protocol (RAMP) is used to manage the sharing of buffers between the Guest and Host. It configures the memory regions as Protected EMPTY or Protected RAM by calling RSI_IPA_STATE_SET command. The RAMP provides interfaces that device drivers can use to open/close apertures for sharing buffers. The RAMP also keeps track of the apertures that have been opened and closes them on ExitBootServices. It also registers for reset notification and closes all open apertures before the platform resets the system. Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Gerd Hoffmann Signed-off-by: Sami Mujawar --- ArmVirtPkg/ArmVirtPkg.dec | 3 + ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h | 103 +++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c | 658 ++++++++++++++++++++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf | 48 ++ 4 files changed, 812 insertions(+) diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec index d521e107ddff15e6dc585e3a63567e3ad817189f..a6701ed3f88b9976110992dda22c11eea735cc4c 100644 --- a/ArmVirtPkg/ArmVirtPkg.dec +++ b/ArmVirtPkg/ArmVirtPkg.dec @@ -44,6 +44,9 @@ [PcdsFeatureFlag] # gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|FALSE|BOOLEAN|0x00000004 +[Protocols] + gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } } + [PcdsFixedAtBuild, PcdsPatchableInModule] ## # This is the physical address of Rsdp which is the core struct of Acpi. diff --git a/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h new file mode 100644 index 0000000000000000000000000000000000000000..0f45fd296fd54ec536ed3d4bd7725350ab487295 --- /dev/null +++ b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h @@ -0,0 +1,103 @@ +/** @file + Realm Aperture Management Protocol (RAMP) + On Arm CCA Systems the Realm protects access and visibility of Guest memory + and code execution from software outside the realm. + + However, software executing in a Realm needs to interact with the external + world. This may be done using virtualised disk, network interfaces, etc. + The drivers for these virtualised devices need to share buffers with the host + OS to exchange information/data. + + Since the Guest memory is protected by the Realm, the host cannot access these + buffers unless the IPA state of the buffers is changed to Protected EMPTY by + the software executing in the Realm. + + By enabling the sharing of the buffers, we are essentially opening an + aperture so that the host OS can access the range of pages that are shared. + + The virtual firmware (Guest firmware) needs a mechanism to manage the sharing + of buffers. The Realm Aperture Management Protocol provides an interface that + UEFI drivers/modules can use to enable/disable the sharing of buffers with the + Host. The protocol also tracks open apertures and ensures they are shut on + ExitBootServices. + + Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - RAMP - Realm Aperture Management Protocol +**/ + +#ifndef REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ +#define REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ + +/** This macro defines the Realm Aperture Management Protocol GUID. + + GUID: {585C00BE-CF7C-4DB8-8AA2-490D67F5F6E6} +*/ +#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_GUID \ + { 0x585c00be, 0xcf7c, 0x4db8, \ + { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } \ + }; + +/** This macro defines the Realm Aperture Management Protocol Revision. +*/ +#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION 0x00010000 + +#pragma pack(1) + +/** Enables sharing of the memory buffers with the host. + + @param [in] Memory Pointer to the page start address. + @param [in] Pages Number of pages to share. + @param [out] ApertureReference Reference to the opened aperture. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_ACCESS_DENIED Aperture already open over memory region. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE)( + IN CONST EFI_PHYSICAL_ADDRESS Memory, + IN CONST UINTN Pages, + OUT EFI_HANDLE *CONST ApertureReference + ); + +/** Disables the sharing of the buffers. + + @param [in] ApertureReference Reference to the aperture for closing. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The required buffer information is not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE)( + IN CONST EFI_HANDLE ApertureReference + ); + +/** A structure describing the interface provided by the Realm Aperture + Management Protocol. +*/ +typedef struct RealmApertureManagementProtocol { + /// The Realm Aperture Management Protocol revision. + UINT64 Revision; + + /// Shares Realm Pages(s) with the Host. + EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE OpenAperture; + + /// Makes the Realm Pages(s) private to the Realm. + EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE CloseAperture; +} EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL; + +/** The Realm Aperture Management Protocol GUID. +*/ +extern EFI_GUID gEfiRealmApertureManagementProtocolGuid; + +#pragma pack() + +#endif // REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c new file mode 100644 index 0000000000000000000000000000000000000000..991054d47b10b45ed5c211827e795d88f8942c02 --- /dev/null +++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c @@ -0,0 +1,658 @@ +/** @file + Realm Aperture Management Protocol Dxe + + Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - IPA - Intermediate Physical Address + - RAMP - Realm Aperture Management Protocol + - RIPAS - Realm IPA state + - RSI - Realm Service Interface +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + A macro defining the signature for the aperture information structure. +*/ +#define APERTURE_INFO_SIG SIGNATURE_64 ('A', 'P', 'E', 'R', 'T', 'U', 'R', 'E') + +/** + A structure describing the aperture. +*/ +typedef struct { + /// Signature for identifying this structure. + UINT64 Signature; + + /// The linked list entry. + LIST_ENTRY Link; + + /// The base address for the start of the aperture. + EFI_PHYSICAL_ADDRESS BaseAddress; + + /// The number of pages covered by the aperture. + UINTN Pages; + + /// The bit mask of attributes for the memory region. The + /// bit mask of available attributes is defined in GetMemoryMap(). + UINT64 MemoryAttributes; + + /// The RIPAS for the aperture. + RIPAS Ripas; +} APERTURE_INFO; + +/** + List of the APERTURE_INFO structures that have been set up by OpenAperture() + and not yet torn down by CloseAperture(). The list represents the full set + of open apertures currently in effect. +*/ +STATIC +LIST_ENTRY mApertureInfos = INITIALIZE_LIST_HEAD_VARIABLE (mApertureInfos); + +/** + A local variable to store the IPA width of the Realm. The IPA width + of the Realm is required to configure the protection attribute of + memory regions. +*/ +STATIC UINT64 mIpaWidth; + +/** Checks if an open aperture is overlapping the memory region. + + @param [in] MemStart Pointer to the page start address. + @param [in] Pages Number of pages to share. + + @retval TRUE If memory region overlaps an open aperture. + @retval FALSE Memory region does not overlap any open apertures. +**/ +STATIC +BOOLEAN +EFIAPI +IsApertureOverlapping ( + IN CONST EFI_PHYSICAL_ADDRESS MemStart, + IN CONST UINTN Pages + ) +{ + LIST_ENTRY *Node; + LIST_ENTRY *NextNode; + APERTURE_INFO *ApertureInfo; + EFI_PHYSICAL_ADDRESS MemEnd; + EFI_PHYSICAL_ADDRESS ApertureStart; + EFI_PHYSICAL_ADDRESS ApertureEnd; + + MemEnd = MemStart + (EFI_PAGE_SIZE * Pages) - 1; + + // All drivers that had opened the apertures have halted their respective + // controllers by now; close all the apertures. + for ( + Node = GetFirstNode (&mApertureInfos); + Node != &mApertureInfos; + Node = NextNode + ) + { + NextNode = GetNextNode (&mApertureInfos, Node); + ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); + ApertureStart = ApertureInfo->BaseAddress; + ApertureEnd = ApertureStart + (EFI_PAGE_SIZE * ApertureInfo->Pages) - 1; + + if (((ApertureStart >= MemStart) && (ApertureStart <= MemEnd)) || + ((ApertureEnd >= MemStart) && (ApertureEnd <= MemEnd)) || + ((MemStart >= ApertureStart) && (MemStart <= ApertureEnd)) || + ((MemEnd >= ApertureStart) && (MemEnd <= ApertureEnd))) + { + return TRUE; + } + } + + return FALSE; +} + +/** Enables sharing of the memory buffers with the host. + + @param [in] Memory Pointer to the page start address. + @param [in] Pages Number of pages to share. + @param [out] ApertureReference Reference to the opened aperture. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_ACCESS_DENIED Aperture already open over memory region. +**/ +STATIC +EFI_STATUS +EFIAPI +RampOpenAperture ( + IN CONST EFI_PHYSICAL_ADDRESS Memory, + IN CONST UINTN Pages, + OUT EFI_HANDLE *CONST ApertureReference + ) +{ + EFI_STATUS Status; + EFI_STATUS Status1; + APERTURE_INFO *ApertInfo; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + EFI_PHYSICAL_ADDRESS MemRangeAddr; + UINTN Index; + + if ((Memory == 0) || + (Pages == 0) || + (ApertureReference == NULL) || + ((Memory & (EFI_PAGE_SIZE - 1)) != 0)) + { + return EFI_INVALID_PARAMETER; + } + + // The pages size must be aligned to the Realm Granule size. + STATIC_ASSERT ((EFI_PAGE_SIZE & (REALM_GRANULE_SIZE - 1)) == 0); + + // Checks if we already have an open aperture that overlaps the + // memory region. If so return the request as invalid. + if (IsApertureOverlapping (Memory, Pages)) { + return EFI_INVALID_PARAMETER; + } + + MemRangeAddr = Memory; + for (Index = 0; Index < Pages; Index++) { + Status = gDS->GetMemorySpaceDescriptor (MemRangeAddr, &GcdDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG (( + DEBUG_INFO, + "%a: Memory = 0x%lx, MemType = %a\n", + __func__, + MemRangeAddr, + ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) ? + "Runtime Services Memory" : "Boot Services Memory" + )); + + // We currently do not have a usecase where we would want to open apertures + // for runtime services memory + if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { + return EFI_UNSUPPORTED; + } + + MemRangeAddr += EFI_PAGE_SIZE; + } // for + + Status = ArmCcaSetMemoryProtectAttribute ( + Memory, + EFI_PAGES_TO_SIZE (Pages), + mIpaWidth, + TRUE + ); + if (RETURN_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to update page tables for Protected EMPTY page mapping, " + "Address = %p, Pages = 0x%lx, Status = %r\n", + Memory, + Pages, + Status + )); + return Status; + } + + // Allocate a APERTURE_INFO structure to remember the apertures opened. + ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); + if (ApertInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto error_handler1; + } + + InitializeListHead (&ApertInfo->Link); + ApertInfo->Signature = APERTURE_INFO_SIG; + ApertInfo->BaseAddress = Memory; + ApertInfo->Pages = Pages; + ApertInfo->MemoryAttributes = GcdDescriptor.Attributes; + ApertInfo->Ripas = RipasEmpty; + + DEBUG (( + DEBUG_INFO, + "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " + "MemoryAttributes = 0x%x, Ripas = 0x%x\n", + __func__, + ApertInfo, + ApertInfo->BaseAddress, + ApertInfo->Pages, + ApertInfo->MemoryAttributes, + ApertInfo->Ripas + )); + + // Set the Realm IPA state to Empty to open the Aperture + Status = RsiSetIpaState ( + (UINT64 *)Memory, + (Pages * EFI_PAGE_SIZE), + RipasEmpty + ); + if (RETURN_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: RSI Set IPA State failed, Address = %p, Pages = 0x%lx, " + "Status = %r\n", + Memory, + Pages, + Status + )); + goto error_handler; + } + + DEBUG (( + DEBUG_INFO, + "SUCCESS: RSI Set IPA State complete, Address = %p, Pages = 0x%lx, " + "Status = %r\n", + Memory, + Pages, + Status + )); + + InsertHeadList (&mApertureInfos, &ApertInfo->Link); + *ApertureReference = (EFI_HANDLE *)&ApertInfo->Link; + + return Status; + +error_handler: + + FreePool (ApertInfo); + +error_handler1: + Status1 = ArmCcaSetMemoryProtectAttribute ( + Memory, + EFI_PAGES_TO_SIZE (Pages), + mIpaWidth, + FALSE + ); + if (RETURN_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to update page tables to Protected page mapping, " + "Address = %p, Pages = 0x%lx, Status = %r\n", + Memory, + Pages, + Status1 + )); + } + + *ApertureReference = NULL; + // return the first error code + return Status; +} + +/** Disables the sharing of the buffers. + + @param [in] ApertureReference Reference to the aperture for closing. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The required buffer information is not found. +**/ +STATIC +EFI_STATUS +EFIAPI +RampCloseAperture ( + IN CONST EFI_HANDLE ApertureReference + ) +{ + EFI_STATUS Status; + APERTURE_INFO *ApertInfo; + + if (ApertureReference == NULL) { + return EFI_INVALID_PARAMETER; + } + + ApertInfo = NULL; + ApertInfo = CR (ApertureReference, APERTURE_INFO, Link, APERTURE_INFO_SIG); + if (ApertInfo == NULL) { + return EFI_NOT_FOUND; + } + + DEBUG (( + DEBUG_INFO, + "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " + "MemoryAttributes = 0x%x, Ripas = 0x%x\n", + __func__, + ApertInfo, + ApertInfo->BaseAddress, + ApertInfo->Pages, + ApertInfo->MemoryAttributes, + ApertInfo->Ripas + )); + + // Set the Realm IPA state to RAM to close the Aperture + Status = RsiSetIpaState ( + (UINT64 *)ApertInfo->BaseAddress, + (ApertInfo->Pages * EFI_PAGE_SIZE), + RipasRam + ); + if (RETURN_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: RSI Set IPA State failed, Address = %p, Pages = 0x%lx, " + "Status = %r\n", + ApertInfo->BaseAddress, + ApertInfo->Pages, + Status + )); + return Status; + } + + Status = ArmCcaSetMemoryProtectAttribute ( + ApertInfo->BaseAddress, + EFI_PAGES_TO_SIZE (ApertInfo->Pages), + mIpaWidth, + FALSE + ); + if (RETURN_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to update page tables for Protected RAM page mapping," + "Address = %p, Pages = 0x%lx, Status = %r\n", + ApertInfo->BaseAddress, + ApertInfo->Pages, + Status + )); + } + + RemoveEntryList (&ApertInfo->Link); + FreePool (ApertInfo); + + return Status; +} + +/** Closes all open apertures. + +**/ +STATIC +VOID +EFIAPI +RampCloseAllApertures ( + VOID + ) +{ + LIST_ENTRY *Node; + LIST_ENTRY *NextNode; + APERTURE_INFO *ApertureInfo; + + // All drivers that had opened the apertures have halted their respective + // controllers by now; close all the apertures. + for ( + Node = GetFirstNode (&mApertureInfos); + Node != &mApertureInfos; + Node = NextNode + ) + { + NextNode = GetNextNode (&mApertureInfos, Node); + ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); + RampCloseAperture (&ApertureInfo->Link); + } +} + +/** + Notification function that is queued after the notification functions of all + events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. + + This function invokes the closing of all open apertures. + + @param[in] Event Event whose notification function is being invoked. Event + is permitted to request the queueing of this function + only at TPL_CALLBACK task priority level. + + @param[in] Context Ignored. +**/ +STATIC +VOID +EFIAPI +OnRampExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + RampCloseAllApertures (); +} + +/** + Notification function that is queued when gBS->ExitBootServices() signals the + EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another + event, received as Context, and returns. + + Signaling an event in this context is safe. The UEFI spec allows + gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not + listed, hence memory is not allocated. + + @param[in] Event Event whose notification function is being invoked. + Event is permitted to request the queueing of this + function at TPL_CALLBACK or TPL_NOTIFY task + priority level. + + @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal + is permitted to request the queueing of its + notification function only at TPL_CALLBACK level. +**/ +STATIC +VOID +EFIAPI +RampExitBootServices ( + IN EFI_EVENT Event, + IN VOID *EventToSignal + ) +{ + // (1) The NotifyFunctions of all the events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before + // RampExitBootServices() is entered. + // + // (2) RampExitBootServices() is executing minimally at TPL_CALLBACK. + // + // (3) RampExitBootServices() has been queued in unspecified order relative + // to the NotifyFunctions of all the other events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as + // Event's. + // + // Consequences: + // + // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions + // queued at TPL_CALLBACK may be invoked after RampExitBootServices() + // returns. + // + // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions + // queued at TPL_NOTIFY may be invoked after RampExitBootServices() + // returns; plus *all* NotifyFunctions queued at TPL_CALLBACK will be + // invoked strictly after all NotifyFunctions queued at TPL_NOTIFY, + // including RampExitBootServices(), have been invoked. + // + // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we + // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* + // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. + gBS->SignalEvent (EventToSignal); +} + +/** A structure describing the Realm Aperture Management protocol. +*/ +STATIC +CONST +EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL Ramp = { + EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION, + RampOpenAperture, + RampCloseAperture +}; + +/** + This routine is called to close all apertures before system reset. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null- + terminated string, optionally followed by additional + binary data. The string is a description that the + caller may use to further indicate the reason for + the system reset. ResetData is only valid if + ResetStatus is something other than EFI_SUCCESS + unless the ResetType is EfiResetPlatformSpecific + where a minimum amount of ResetData is always + required. + For a ResetType of EfiResetPlatformSpecific the data + buffer also starts with a Null-terminated string + that is followed by an EFI_GUID that describes the + specific type of reset to perform. +**/ +VOID +EFIAPI +OnResetEvent ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + RampCloseAllApertures (); +} + +/** + Hook the system reset to close all apertures. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +OnResetNotificationInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify; + + Status = gBS->LocateProtocol ( + &gEfiResetNotificationProtocolGuid, + NULL, + (VOID **)&ResetNotify + ); + if (!EFI_ERROR (Status)) { + Status = ResetNotify->RegisterResetNotify (ResetNotify, OnResetEvent); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "RAMP: Hook system reset to close all apertures.\n")); + gBS->CloseEvent (Event); + } +} + +/** Entry point for Realm Aperture Management Protocol Dxe + + @param [in] ImageHandle Handle for this image. + @param [in] SystemTable Pointer to the EFI system table. + + @retval EFI_SUCCESS When executing in a Realm the RAMP was + installed successfully. + When execution context is not a Realm, this + function returns success indicating nothing + needs to be done and allow other modules to + run. + @retval EFI_OUT_OF_RESOURCES There was not enough memory to install the + protocols. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + +**/ +EFI_STATUS +EFIAPI +RealmApertureManagementProtocolDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_EVENT CloseAllAperturesEvent; + EFI_EVENT ExitBootEvent; + VOID *Registration; + + // When the execution context is a Realm, install the Realm Aperture + // Management protocol otherwise return success so that other modules + // can run. + if (!IsRealm ()) { + return EFI_SUCCESS; + } + + // Retrieve the IPA Width of the Realm for subsequent use to configure + // the protection attribute of memory regions. + Status = GetIpaWidth (&mIpaWidth); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to get Ipa Width, Status = %r\n", + Status + )); + ASSERT (0); + return Status; + } + + /* + Create the "late" event whose notification function will close all + apertures. + */ + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + OnRampExitBootServicesEvent, // NotifyFunction + NULL, // NotifyContext + &CloseAllAperturesEvent // Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /* + Create the event whose notification function will be queued by + gBS->ExitBootServices() and will signal the event created above. + */ + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type + TPL_CALLBACK, // NotifyTpl + RampExitBootServices, // NotifyFunction + CloseAllAperturesEvent, // NotifyContext + &ExitBootEvent // Event + ); + if (EFI_ERROR (Status)) { + goto error_handler1; + } + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiRealmApertureManagementProtocolGuid, + &Ramp, + NULL + ); + if (!EFI_ERROR (Status)) { + // RAMP Protocol installed successfully + // Hook the system reset to close all apertures. + EfiCreateProtocolNotifyEvent ( + &gEfiResetNotificationProtocolGuid, + TPL_CALLBACK, + OnResetNotificationInstall, + NULL, + &Registration + ); + return Status; + } + + // cleanup on error + gBS->CloseEvent (ExitBootEvent); + +error_handler1: + gBS->CloseEvent (CloseAllAperturesEvent); + return Status; +} diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf new file mode 100644 index 0000000000000000000000000000000000000000..2e3021b82bd75b7f41dc9427117a8394dfde2e68 --- /dev/null +++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf @@ -0,0 +1,48 @@ +## @file +# Module to manage the sharing of buffers in a Realm with the Host. +# +# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = RealmApertureManagementProtocolDxe + FILE_GUID = CEC2F7D5-2564-46D4-A23F-501623F7F56A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RealmApertureManagementProtocolDxeInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + RealmApertureManagementProtocolDxe.c + +[Packages] + ArmVirtPkg/ArmVirtPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmCcaLib + ArmCcaRsiLib + BaseLib + DxeServicesTableLib + MemoryAllocationLib + PrintLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiRealmApertureManagementProtocolGuid ## SOMETIME_PRODUCES + gEfiResetNotificationProtocolGuid ## CONSUMES + +[Depex] + TRUE -- 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)' -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#117697): https://edk2.groups.io/g/devel/message/117697 Mute This Topic: https://groups.io/mt/105483438/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-