/** @file Library that implements the Arm CCA helper functions. Copyright (c) 2022 - 2026, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Glossary: - Rsi or RSI - Realm Service Interface - IPA - Intermediate Physical Address - RIPAS - Realm IPA state **/ #include #include #include #include #include #include #include #include #include #include #include #include #include /** Queries to see if running in a Realm. @retval TRUE The execution is within the context of a Realm. @retval FALSE The execution is not within the context of a Realm. **/ STATIC BOOLEAN EFIAPI ArmCcaReadIsRealm ( VOID ) { RETURN_STATUS Status; UINT32 UefiImpl; UINT32 RmmImplLow; UINT32 RmmImplHigh; // Query the RSI_GET_VERSION. If it is implemented then // RMM is present and we must be running in a Realm. Status = ArmCcaRsiGetVersion ( &UefiImpl, &RmmImplLow, &RmmImplHigh ); if (!RETURN_ERROR (Status)) { return TRUE; } return FALSE; } /** Check if running in a Realm. @retval TRUE The execution is within the context of a Realm. @retval FALSE The execution is not within the context of a Realm. **/ BOOLEAN EFIAPI ArmCcaIsRealm ( VOID ) { BOOLEAN RealmWorld; VOID *HobList; VOID *Hob; UINT64 *IsRealmHobData; if (!ArmHasRme ()) { return FALSE; } HobList = GetHobList (); if (HobList == NULL) { // HOB not initialised. return ArmCcaReadIsRealm (); } RealmWorld = FALSE; Hob = GetFirstGuidHob (&gArmCcaIsRealmGuid); if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) < sizeof (*IsRealmHobData))) { // The gArmCcaIsRealmGuid is created in the PlatformPeim() which // may not have been called for caching the IsRealm value yet. // So, read the Realm value. RealmWorld = ArmCcaReadIsRealm (); } else { // Read the value from the HOB IsRealmHobData = GET_GUID_HOB_DATA (Hob); RealmWorld = *IsRealmHobData; } return RealmWorld; } /** Read the IPA width of the Realm. The IPA width of the Realm is used to configure the protection attribute for memory regions, see ArmCcaSetMemoryProtectionAttribute(). @param [out] IpaWidth IPA width of the Realm. @retval RETURN_SUCCESS Success. @retval RETURN_INVALID_PARAMETER A parameter is invalid. @retval RETURN_OUT_OF_RESOURCES Out of resources. **/ STATIC RETURN_STATUS EFIAPI ArmCcaReadIpaWidth ( OUT UINT64 *IpaWidth ) { RETURN_STATUS Status; ARM_CCA_REALM_CONFIG *Config; if (IpaWidth == NULL) { return RETURN_INVALID_PARAMETER; } Config = AllocateAlignedPages ( EFI_SIZE_TO_PAGES (sizeof (ARM_CCA_REALM_CONFIG)), ARM_CCA_REALM_GRANULE_SIZE ); if (Config == NULL) { ASSERT (0); return RETURN_OUT_OF_RESOURCES; } ZeroMem (Config, sizeof (ARM_CCA_REALM_CONFIG)); Status = ArmCcaRsiGetRealmConfig (Config); if (RETURN_ERROR (Status)) { ASSERT (0); goto ExitHandler; } if (Config->IpaWidth > ArmGetPhysicalAddressBits ()) { ASSERT (0); Status = RETURN_INVALID_PARAMETER; goto ExitHandler; } *IpaWidth = Config->IpaWidth; ExitHandler: FreeAlignedPages (Config, EFI_SIZE_TO_PAGES (sizeof (ARM_CCA_REALM_CONFIG))); return Status; } /** Return the IPA width of the Realm. The IPA width of the Realm is used to configure the protection attribute for memory regions, see ArmCcaSetMemoryProtectionAttribute(). @param [out] IpaWidth IPA width of the Realm. @retval RETURN_SUCCESS Success. @retval RETURN_INVALID_PARAMETER A parameter is invalid. @retval RETURN_UNSUPPORTED The execution is not within the context of a Realm. @retval RETURN_OUT_OF_RESOURCES Out of resources. **/ RETURN_STATUS EFIAPI ArmCcaGetIpaWidth ( OUT UINT64 *IpaWidth ) { RETURN_STATUS Status; VOID *HobList; VOID *Hob; UINT64 *CcaIpaWidth; if (IpaWidth == NULL) { return RETURN_INVALID_PARAMETER; } if (!ArmCcaIsRealm ()) { *IpaWidth = 0; return RETURN_UNSUPPORTED; } HobList = GetHobList (); if (HobList == NULL) { // HOB not initialised. return ArmCcaReadIpaWidth (IpaWidth); } Hob = GetFirstGuidHob (&gArmCcaIpaWidthGuid); if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) < sizeof (UINT64))) { // The gArmCcaIpaWidthGuid is created in the PlatformPeim() which // may not have been called for caching the IpaWidth value yet. // So, read the IPA Width value. Status = ArmCcaReadIpaWidth (IpaWidth); if (RETURN_ERROR (Status)) { ASSERT (0); return Status; } } else { // Read the value from the HOB. CcaIpaWidth = GET_GUID_HOB_DATA (Hob); if ((UINT64)*CcaIpaWidth == 0) { return RETURN_NOT_FOUND; } *IpaWidth = *CcaIpaWidth; } return RETURN_SUCCESS; } /** Check if the address range is protected MMIO @param [in] BaseAddress Base address of the device MMIO region. @param [in] Length Length of the device MMIO region. @param [out] IsProtectedMmio TRUE - if the RIPAS for the address range is protected MMIO. FALSE - if the RIPAS for the address range is not protected MMIO. @retval RETURN_SUCCESS Success. @retval RETURN_INVALID_PARAMETER A parameter is invalid. @retval RETURN_UNSUPPORTED The request is not initiated in a Realm. **/ RETURN_STATUS EFIAPI ArmCcaMemRangeIsProtectedMmio ( IN UINT64 BaseAddress, IN UINT64 Length, OUT BOOLEAN *IsProtectedMmio ) { RETURN_STATUS RetStatus; UINT64 *Base; UINT64 *Top; UINT64 *End; ARM_CCA_RIPAS State; if ((Length == 0) || (IsProtectedMmio == NULL)) { return RETURN_INVALID_PARAMETER; } Base = (UINT64 *)BaseAddress; End = (UINT64 *)(BaseAddress + Length); while (Base < End) { Top = End; RetStatus = ArmCcaRsiGetIpaState ( Base, &Top, &State ); if (RETURN_ERROR (RetStatus)) { // An error occurred. return RetStatus; } if (State != RipasDev) { // The address range is not protected MMIO. *IsProtectedMmio = FALSE; return RetStatus; } Base = Top; } // while *IsProtectedMmio = TRUE; return RETURN_SUCCESS; }