summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarrison Mutai <harrison.mutai@arm.com>2026-05-15 15:46:20 +0100
committerHarrison Mutai <harrison.mutai@arm.com>2026-06-29 13:37:46 +0100
commit1cdb2e13ae7147b11f65f8cd6be0de9871fb3b20 (patch)
tree760bf628e231e78d87adcd2a966bc7874db90680
parent0ff6f48335d66e69cfdc42bb9c4d49a43b819bfc (diff)
downloadarm-trusted-firmware-1cdb2e13ae7147b11f65f8cd6be0de9871fb3b20.tar.gz
arm-trusted-firmware-1cdb2e13ae7147b11f65f8cd6be0de9871fb3b20.zip
feat(firme): introduce FIRME MECID service
Add the FIRME MECID management ABI and service implementation, advertise the service through the base feature register when available, and provide platform hooks for MEC refresh. Change-Id: I1a1a2f2dd615274956d0db85049b0d6760fbcbc4 Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
-rw-r--r--bl31/bl31.mk3
-rw-r--r--include/arch/aarch64/arch.h3
-rw-r--r--include/services/firme_svc.h26
-rw-r--r--plat/arm/board/fvp/fvp_common.c8
-rw-r--r--plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c11
-rw-r--r--plat/qemu/common/qemu_common.c12
-rw-r--r--services/std_svc/firme/firme_base_service.c12
-rw-r--r--services/std_svc/firme/firme_main.c5
-rw-r--r--services/std_svc/firme/firme_mecid.c79
9 files changed, 152 insertions, 7 deletions
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 3a645d014..29b79e173 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -216,7 +216,8 @@ endif
ifeq (${FIRME_SUPPORT},1)
BL31_SOURCES += services/std_svc/firme/firme_main.c \
services/std_svc/firme/firme_base_service.c \
- services/std_svc/firme/firme_granule_management_service.c
+ services/std_svc/firme/firme_granule_management_service.c \
+ services/std_svc/firme/firme_mecid.c
endif
BL31_DEFAULT_LINKER_SCRIPT_SOURCE := bl31/bl31.ld.S
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index bbd04ded1..4aa8035f3 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1992,8 +1992,9 @@
* FEAT_MEC - Memory Encryption Contexts
******************************************************************************/
#define MECIDR_EL2 S3_4_C10_C8_7
-#define MECIDR_EL2_MECIDWidthm1_MASK U(0xf)
#define MECIDR_EL2_MECIDWidthm1_SHIFT U(0)
+#define MECIDR_EL2_MECIDWidthm1_WIDTH U(4)
+#define MECIDR_EL2_MECIDWidthm1_MASK GENMASK(3, 0)
/******************************************************************************
* FEAT_FGWTE3 - Fine Grained Write Trap
diff --git a/include/services/firme_svc.h b/include/services/firme_svc.h
index c229d116b..052c1077f 100644
--- a/include/services/firme_svc.h
+++ b/include/services/firme_svc.h
@@ -110,7 +110,10 @@ typedef struct {
#define FIRME_BASE_MAX_SH_BUF_PG_CNT_MASK U(0x3FFF)
#define FIRME_BASE_SERVICE_LIST_SHIFT U(16)
#define FIRME_BASE_SERVICE_LIST_MASK U(0xFFFF)
-#define FIRME_BASE_SERVICE_GRANULE_MGMT_BIT BIT(16)
+#define FIRME_BASE_SERVICE_BIT(_id) BIT((_id) + \
+ FIRME_BASE_SERVICE_LIST_SHIFT)
+#define FIRME_BASE_SERVICE_GRANULE_MGMT_BIT FIRME_BASE_SERVICE_BIT(0)
+#define FIRME_BASE_SERVICE_MECID_BIT FIRME_BASE_SERVICE_BIT(2)
/* Granule management service feature register definitions. */
#define FIRME_GM_GPI_SET_BIT BIT(0)
@@ -205,7 +208,17 @@ typedef struct {
#define FIRME_IDE_KEYSET_POLL SMC64_FIRME_FID(U(0x6))
/* MECID management service */
-#define FIRME_MEC_REFRESH SMC64_FIRME_FID(U(0x7))
+#define FIRME_MEC_REFRESH_FID SMC64_FIRME_FID(U(0x7))
+
+#define MEC_REFRESH_REASON_REALM_CREATE U(0)
+#define MEC_REFRESH_REASON_REALM_DESTROY U(1)
+
+#define MEC_PARAM_MECID_SHIFT U(32)
+#define MEC_PARAM_MECID_WIDTH U(16)
+#define MEC_PARAM_MECID_MASK MASK(MEC_PARAM_MECID)
+
+#define FIRME_MECID_FEATURE_REG_COUNT U(1)
+#define FIRME_MECID_FEAT_REG0_MEC_REFRESH_BIT BIT(0)
/* Attestation service */
#define FIRME_ATTEST_PAT_GET SMC64_FIRME_FID(U(0x8))
@@ -224,6 +237,9 @@ uint64_t firme_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie, void *handle, uint64_t flags);
firme_service_info_t *firme_granule_mgmt_service_get_info(void);
+firme_service_info_t *firme_mecid_service_get_info(void);
+
+int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason);
u_register_t firme_base_service_handler(firme_instance_e instance, uint32_t smc_fid,
uint64_t x1, uint64_t x2, uint64_t x3,
@@ -236,4 +252,10 @@ u_register_t firme_granule_mgmt_service_handler(firme_instance_e instance,
uint64_t x4, void *cookie,
void *handle, uint64_t flags);
+u_register_t firme_mecid_service_handler(firme_instance_e instance,
+ uint32_t smc_fid, uint64_t x1,
+ uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie,
+ void *handle, uint64_t flags);
+
#endif /* FIRME_SVC_H */
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index af32ad20f..4aafc0530 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2026, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -23,6 +23,7 @@
#include <platform_def.h>
#include <services/arm_arch_svc.h>
#include <services/rmm_core_manifest.h>
+#include <services/firme_svc.h>
#if SPM_MM
#include <services/spm_mm_partition.h>
#endif
@@ -1073,4 +1074,9 @@ int plat_rmmd_mecid_key_update(uint16_t mecid, unsigned int reason)
*/
return 0;
}
+
+int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason)
+{
+ return 0;
+}
#endif /* ENABLE_RMM */
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
index 8a7ddc420..aa4cec63e 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
@@ -10,6 +10,7 @@
#include <drivers/arm/sfcp.h>
#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
+#include <services/firme_svc.h>
#include <platform_def.h>
#include <nrd_plat.h>
@@ -197,6 +198,16 @@ int plat_rmmd_mecid_key_update(uint16_t mecid, unsigned int reason)
return 0;
}
+int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason)
+{
+ /*
+ * RDV3 does not support FEAT_MEC.
+ * FIXME: This hook is needed to maintain backward compatibility with RMMD. Drop once we
+ * have more fine grained control over what services are exposed and how.
+ */
+ return 0;
+}
+
int plat_spmd_handle_group0_interrupt(uint32_t intid)
{
/*
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index f5e19b9b1..97625bd49 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2026, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,7 @@
#include <common/bl_common.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <services/el3_spmc_ffa_memory.h>
+#include <services/firme_svc.h>
#if ENABLE_RMM
#include <services/rmm_core_manifest.h>
#endif
@@ -768,6 +769,15 @@ int plat_rmmd_mecid_key_update(uint16_t mecid, unsigned int reason)
*/
return 0;
}
+
+int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason)
+{
+ /*
+ * QEMU does not provide an interface to change the encryption key
+ * associated with MECID. Hence always return success.
+ */
+ return 0;
+}
#endif /* ENABLE_RMM */
/**
diff --git a/services/std_svc/firme/firme_base_service.c b/services/std_svc/firme/firme_base_service.c
index 27c414a00..347f8f980 100644
--- a/services/std_svc/firme/firme_base_service.c
+++ b/services/std_svc/firme/firme_base_service.c
@@ -45,6 +45,12 @@ static uint64_t firme_base_get_feat_reg_1(firme_instance_e instance)
reg |= FIRME_BASE_SERVICE_GRANULE_MGMT_BIT;
}
+ info = firme_mecid_service_get_info();
+ if ((info != NULL) &&
+ ((info->instance_support & BIT(instance)) != 0U)) {
+ reg |= FIRME_BASE_SERVICE_MECID_BIT;
+ }
+
return reg;
}
@@ -64,6 +70,9 @@ static int32_t get_firme_service_version(firme_instance_e instance,
case FIRME_GRANULE_MGMT_ID:
info = firme_granule_mgmt_service_get_info();
break;
+ case FIRME_MECID_MGMT_ID:
+ info = firme_mecid_service_get_info();
+ break;
default:
return FIRME_NOT_SUPPORTED;
}
@@ -99,6 +108,9 @@ static int32_t get_firme_feature_reg(uint64_t *reg, firme_instance_e instance,
case FIRME_GRANULE_MGMT_ID:
info = firme_granule_mgmt_service_get_info();
break;
+ case FIRME_MECID_MGMT_ID:
+ info = firme_mecid_service_get_info();
+ break;
}
if ((info != NULL) && (reg_index < info->num_feature_regs) &&
diff --git a/services/std_svc/firme/firme_main.c b/services/std_svc/firme/firme_main.c
index c2bf33d4b..59b77fc52 100644
--- a/services/std_svc/firme/firme_main.c
+++ b/services/std_svc/firme/firme_main.c
@@ -53,7 +53,7 @@ static inline bool is_ide_key_mgmt_service_fid(uint32_t fid)
static inline bool is_mecid_service_fid(uint32_t fid)
{
- if (fid == FIRME_MEC_REFRESH) {
+ if (fid == FIRME_MEC_REFRESH_FID) {
return true;
} else {
return false;
@@ -120,6 +120,9 @@ uint64_t firme_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
}
else if (is_mecid_service_fid(smc_fid)) {
+ return firme_mecid_service_handler(instance, smc_fid, x1, x2,
+ x3, x4, cookie, handle,
+ flags);
}
else if (is_attestation_service_fid(smc_fid)) {
diff --git a/services/std_svc/firme/firme_mecid.c b/services/std_svc/firme/firme_mecid.c
new file mode 100644
index 000000000..b68d9f655
--- /dev/null
+++ b/services/std_svc/firme/firme_mecid.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2026, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <services/firme_svc.h>
+#include <smccc_helpers.h>
+
+/* Only supported ABI is MEC_REFRESH for Realm callers. */
+static firme_service_info_t mecid_info = {
+ .version = FIRME_VERSION(FIRME_MECID_MGMT_VERSION_MAJOR,
+ FIRME_MECID_MGMT_VERSION_MINOR),
+ .instance_support = BIT(FIRME_REALM),
+ .num_feature_regs = FIRME_MECID_FEATURE_REG_COUNT,
+ .feature_reg = { FIRME_MECID_FEAT_REG0_MEC_REFRESH_BIT },
+};
+
+firme_service_info_t *firme_mecid_service_get_info(void)
+{
+ if (!is_feat_mec_supported()) {
+ return NULL;
+ }
+
+ return &mecid_info;
+}
+
+static int firme_mec_refresh(u_register_t mec_params)
+{
+ uint64_t common_mecid_width;
+ uint16_t mecid;
+
+ /*
+ * Check whether FEAT_MEC is supported by the hardware. If not, return
+ * unknown SMC.
+ */
+ if (!is_feat_mec_supported()) {
+ return FIRME_NOT_SUPPORTED;
+ }
+
+ /*
+ * Check whether the MECID parameter fits within the common MECID width.
+ */
+ common_mecid_width = ((read_mecidr_el2() >> MECIDR_EL2_MECIDWidthm1_SHIFT) &
+ MECIDR_EL2_MECIDWidthm1_MASK) + 1UL;
+ mecid = EXTRACT(MEC_PARAM_MECID, mec_params);
+
+ if (mecid > common_mecid_width) {
+ return FIRME_INVALID_PARAMETERS;
+ }
+
+ return plat_firme_mec_refresh(mecid, mec_params & BIT(0));
+}
+
+u_register_t firme_mecid_service_handler(firme_instance_e instance,
+ uint32_t smc_fid, uint64_t x1,
+ uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie,
+ void *handle, uint64_t flags)
+{
+ (void)instance;
+ (void)x2;
+ (void)x3;
+ (void)x4;
+ (void)cookie;
+ (void)handle;
+ (void)flags;
+
+ if (smc_fid != FIRME_MEC_REFRESH_FID || instance != FIRME_REALM) {
+ SMC_RET1(handle, FIRME_NOT_SUPPORTED);
+ }
+
+ SMC_RET1(handle, firme_mec_refresh(x1));
+}