public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Sami Mujawar" <sami.mujawar@arm.com>
To: <devel@edk2.groups.io>
Cc: Sami Mujawar <sami.mujawar@arm.com>, <ardb+tianocore@kernel.org>,
	<quic_llindhol@quicinc.com>, <kraxel@redhat.com>,
	<Pierre.Gondois@arm.com>, <Suzuki.Poulose@arm.com>,
	<jean-philippe@linaro.org>, <Matteo.Carlini@arm.com>,
	<Akanksha.Jain2@arm.com>, <Ben.Adderson@arm.com>, <nd@arm.com>
Subject: [RFC PATCH v1 26/30] ArmVirtPkg: Introduce Realm Aperture Management Protocol
Date: Tue, 25 Apr 2023 17:04:24 +0100	[thread overview]
Message-ID: <20230425160428.27980-27-sami.mujawar@arm.com> (raw)
In-Reply-To: <20230425160428.27980-1-sami.mujawar@arm.com>

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.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmVirtPkg/ArmVirtPkg.dec                                                            |   3 +
 ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h                        | 103 +++
 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c   | 656 ++++++++++++++++++++
 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf |  48 ++
 4 files changed, 810 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec
index c61ed9c492e97aa00ba9dbab1a5544354b6e7de7..5f5fb0f0d911f871ffdf0d8e7d1d181d31093679 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 where the device tree is expected to be stored
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.<BR>
+
+  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..f6c31125209468cfe24c4ea4b0eb74e08fe3e2f2
--- /dev/null
+++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c
@@ -0,0 +1,656 @@
+/** @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 <Base.h>
+#include <Library/ArmCcaLib.h>
+#include <Library/ArmCcaRsiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/RealmApertureManagementProtocol.h>
+#include <Protocol/ResetNotification.h>
+
+/**
+  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]  Memory             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            = RIPAS_EMPTY;
+
+  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),
+             RIPAS_EMPTY
+             );
+  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,
+              TRUE
+              );
+  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 = NULL;
+
+  if (ApertureReference == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  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),
+             RIPAS_RAM
+             );
+  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 = NULL;
+  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;
+  }
+
+  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)'


  parent reply	other threads:[~2023-04-25 16:05 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-25 16:03 [RFC PATCH v1 00/30] Support for Arm CCA guest firmware Sami Mujawar
2023-04-25 16:03 ` [RFC PATCH v1 01/30] ArmVirtPkg: kvmtool: Add Emulated Runtime variable support Sami Mujawar
2023-05-10 11:32   ` [edk2-devel] " Ard Biesheuvel
2023-05-15 10:36     ` Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 02/30] ArmPkg: Add helper function to detect RME Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 03/30] ArmPkg: Export SetMemoryRegionAttribute in ArmMmuLib Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 04/30] ArmPkg: Extend number of parameter registers in SMC call Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 05/30] ArmPkg & ArmVirtPkg: Make PcdMonitorConduitHvc a dynamic PCD Sami Mujawar
2023-05-10 11:38   ` Ard Biesheuvel
2023-05-15 10:37     ` Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 06/30] ArmVirtPkg: Add Arm CCA Realm Service Interface Library Sami Mujawar
2023-05-04 12:59   ` [edk2-devel] " Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 07/30] ArmVirtPkg: ArmCcaRsiLib: Add interfaces to manage the Realm IPA state Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 08/30] ArmVirtPkg: ArmCcaRsiLib: Add an interface to get an attestation token Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 09/30] ArmVirtPkg: ArmCcaRsiLib: Add interfaces to get/extend REMs Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 10/30] ArmVirtPkg: ArmCcaRsiLib: Add an interface to make a RSI Host Call Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 11/30] ArmVirtPkg: Define a GUID HOB for IPA width of a Realm Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 12/30] ArmVirtPkg: Add library for Arm CCA initialisation in PEI Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 13/30] ArmVirtPkg: Add NULL instance of ArmCcaInitPeiLib Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 14/30] ArmVirtPkg: Add library for Arm CCA helper functions Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 15/30] ArmVirtPkg: Add Null instance of ArmCcaLib Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 16/30] ArmVirtPkg: Define an interface to configure MMIO regions for Arm CCA Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 17/30] ArmVirtPkg: CloudHv: Add a NULL implementation of ArmCcaConfigureMmio Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 18/30] ArmVirtPkg: Qemu: " Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 19/30] ArmVirtPkg: Xen: " Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 20/30] ArmVirtPkg: Configure the MMIO regions for Arm CCA Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 21/30] ArmVirtPkg: Kvmtool: Use Null version of DebugLib in PrePi Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 22/30] ArmVirtPkg: Add Arm CCA libraries for Kvmtool guest firmware Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 23/30] ArmVirtPkg: Arm CCA configure system memory in early Pei Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 24/30] ArmVirtPkg: Perform Arm CCA initialisation in the Pei phase Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 25/30] ArmVirtPkg: Add ArmCcaDxe for early DXE phase initialisation Sami Mujawar
2023-05-10 12:08   ` Ard Biesheuvel
2023-05-15 10:39     ` Sami Mujawar
2023-04-25 16:04 ` Sami Mujawar [this message]
2023-04-25 16:04 ` [RFC PATCH v1 27/30] ArmVirtPkg: IoMMU driver to DMA from Realms Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 28/30] ArmVirtPkg: Enable Virtio communication for Arm CCA Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 29/30] MdePkg: Warn if AArch64 RNDR instruction is not supported Sami Mujawar
2023-04-25 16:04 ` [RFC PATCH v1 30/30] ArmVirtPkg: Kvmtool: Switch to use BaseRng for AArch64 Sami Mujawar
2023-05-04 15:13 ` [RFC PATCH v1 00/30] Support for Arm CCA guest firmware Jean-Philippe Brucker
2023-05-04 15:36   ` Ard Biesheuvel
2023-05-05  9:51     ` Jean-Philippe Brucker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230425160428.27980-27-sami.mujawar@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox