diff options
| author | Harrison Mutai <harrison.mutai@arm.com> | 2026-06-18 13:03:00 +0100 |
|---|---|---|
| committer | Harrison Mutai <harrison.mutai@arm.com> | 2026-06-29 13:37:46 +0100 |
| commit | dd6bd54c40c7f51e59428afb31a4e79fa2ef0e07 (patch) | |
| tree | 3eef60918134a52430786528416730eceb5f26c6 | |
| parent | 460c722841566b05e7afd8f3e4072dad624453e2 (diff) | |
| download | arm-trusted-firmware-dd6bd54c40c7f51e59428afb31a4e79fa2ef0e07.tar.gz arm-trusted-firmware-dd6bd54c40c7f51e59428afb31a4e79fa2ef0e07.zip | |
feat(firme): add COMMON_MECID_WIDTH feat reporting
Introduce COMMON_MECID_WIDTH in the FIRME MECID feature registers. The
value is initialized as the minimum of the architectural MECID width and
the maximum MECID width supported by platform peripherals. Note, this
feature register was accidentally omitted from ALP2 version of the
specification. It will be added in the next version of the
specification.
Change-Id: I6766c319b81dabacef76f771546ef7979e98c07d
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
| -rw-r--r-- | docs/porting-guide.rst | 21 | ||||
| -rw-r--r-- | include/services/firme/firme_mecid.h | 61 | ||||
| -rw-r--r-- | include/services/firme_svc.h | 9 | ||||
| -rw-r--r-- | plat/arm/board/fvp/fvp_common.c | 11 | ||||
| -rw-r--r-- | plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c | 8 | ||||
| -rw-r--r-- | plat/qemu/common/qemu_common.c | 8 | ||||
| -rw-r--r-- | services/std_svc/firme/firme_main.c | 5 | ||||
| -rw-r--r-- | services/std_svc/firme/firme_mecid.c | 23 | ||||
| -rw-r--r-- | services/std_svc/std_svc_setup.c | 6 |
9 files changed, 148 insertions, 4 deletions
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 30d5f751c..3372c1e0a 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -2365,6 +2365,27 @@ RMM image and stores it in the area specified by manifest. When ENABLE_RMM is disabled, this function is not used. +Function : plat_firme_get_common_mecid_width() [when FIRME_SUPPORT == 1] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : void + Return : uint8_t + +This function is invoked by BL31's FIRME MECID management service during +initialization to obtain the system MECID width. This is the smallest supported +MECID width for the entire system. + +The returned value uses the same encoding as ``MECIDR_EL2.MECIDWidthm1``. That +is, it is the system MECID width minus one. The common MECID width is defined as +the smallest MECID width supported across the entire system (see rule IQDYKJ in +the M.b version of the Arm ARM for details). The FIRME MECID management service +advertises the returned value in FIRME MECID feature register 1. + +This function needs to be implemented by a platform if it enables FIRME support +and advertises the FIRME MECID management service. + Function : plat_firme_mec_refresh() [when FIRME_SUPPORT == 1] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/services/firme/firme_mecid.h b/include/services/firme/firme_mecid.h new file mode 100644 index 000000000..7ec043350 --- /dev/null +++ b/include/services/firme/firme_mecid.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FIRME_MEC_H +#define FIRME_MEC_H + +#include <stdint.h> + +#include <services/firme/firme_abi.h> + +#define FIRME_MECID_MGMT_VERSION_MAJOR U(1) +#define FIRME_MECID_MGMT_VERSION_MINOR U(0) + +#define FIRME_MEC_FNUM_REFRESH U(0x7) + +/* + * FIRME_MEC_REFRESH + * + * This function refreshes the MEC linked to a given MECID by invalidating the + * existing MEC, generating a new one, and associating the new MEC with that MECID. + * + * Supported from v1.0 + * + * Arguments + * arg0(w0): Function ID 0xC4000407 + * arg1(x1): MEC params Bits[63:48]: Reserved (SBZ). + * Bits[47:32]: MECID. + * Bits[31:1]: Reserved (SBZ). + * Bits[0]: MEC refresh reason. + * – 0b’0: Realm creation. + * – 0b’1: Realm destruction + * + * Return + * ret0(x0): Status FIRME_SUCCESS + * FIRME_NOT_SUPPORTED + * FIRME_INVALID_PARAMETERS + * FIRME_RETRY + */ +#define FIRME_MEC_REFRESH_FID FIRME_FID(FIRME_MEC_FNUM_REFRESH) + +#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(2) +#define FIRME_MECID_FEAT_REG0_MEC_REFRESH_BIT BIT(0) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_SHIFT U(0) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_WIDTH U(4) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_MASK MASK(FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS) + +int32_t firme_mecid_service_init(void); +int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason); +uint8_t plat_firme_get_common_mecid_width(void); + +#endif /* FIRME_MEC_H */ diff --git a/include/services/firme_svc.h b/include/services/firme_svc.h index cf7ecabb2..483de0862 100644 --- a/include/services/firme_svc.h +++ b/include/services/firme_svc.h @@ -217,8 +217,11 @@ typedef struct { #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_FEATURE_REG_COUNT U(2) #define FIRME_MECID_FEAT_REG0_MEC_REFRESH_BIT BIT(0) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_SHIFT U(0) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_WIDTH U(4) +#define FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_MASK MASK(FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS) /* Attestation service */ #define FIRME_ATTEST_PAT_GET_FID SMC64_FIRME_FID(U(0x8)) @@ -233,13 +236,17 @@ typedef struct { #define FIRME_IDEV_OP_CONTINUE_FID SMC64_FIRME_FID(U(0x11)) /* Top level handler for FIRME SMC calls. */ +int32_t firme_init(void); + 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); +int32_t firme_mecid_service_init(void); int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason); +uint8_t plat_firme_get_common_mecid_width(void); u_register_t firme_base_service_handler(firme_instance_e instance, uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c index 3733eee30..0e8f0ac14 100644 --- a/plat/arm/board/fvp/fvp_common.c +++ b/plat/arm/board/fvp/fvp_common.c @@ -5,6 +5,7 @@ */ #include <assert.h> +#include <stdint.h> #include <string.h> #include <arch.h> @@ -1074,4 +1075,14 @@ int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason) */ return 0; } + +uint8_t plat_firme_get_common_mecid_width(void) +{ + + /* + * Use the PE MECID width as the system MECID width is expected to be the same for all + * system components on FVP. + */ + return (uint8_t)EXTRACT(MECIDR_EL2_MECIDWidthm1, read_mecidr_el2()); +} #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 ad25d570d..d0c3a7dd6 100644 --- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c +++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include <stdint.h> + #include <common/debug.h> #include <drivers/arm/gic600_multichip.h> #include <drivers/arm/mhu.h> @@ -199,6 +201,12 @@ int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason) return 0; } +uint8_t plat_firme_get_common_mecid_width(void) +{ + /* RDV3 does not support FEAT_MEC. */ + return 0U; +} + 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 3bdc02f4d..3c19f6ba5 100644 --- a/plat/qemu/common/qemu_common.c +++ b/plat/qemu/common/qemu_common.c @@ -5,10 +5,12 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include <stdint.h> #include <string.h> #include <platform_def.h> +#include <arch.h> #include <arch_helpers.h> #include <common/bl_common.h> #include <lib/xlat_tables/xlat_tables_v2.h> @@ -769,6 +771,12 @@ int plat_firme_mec_refresh(uint16_t mecid, uint8_t reason) */ return 0; } + +uint8_t plat_firme_get_common_mecid_width(void) +{ + /* Safe default value for common MECID width. */ + return (uint8_t)EXTRACT(MECIDR_EL2_MECIDWidthm1, read_mecidr_el2()); +} #endif /* ENABLE_RMM */ /** diff --git a/services/std_svc/firme/firme_main.c b/services/std_svc/firme/firme_main.c index dfbedbe43..96cde89fc 100644 --- a/services/std_svc/firme/firme_main.c +++ b/services/std_svc/firme/firme_main.c @@ -99,6 +99,11 @@ static inline firme_instance_e get_instance_from_flags(uint64_t flags) panic(); } +int32_t firme_init(void) +{ + return firme_mecid_service_init(); +} + 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) { diff --git a/services/std_svc/firme/firme_mecid.c b/services/std_svc/firme/firme_mecid.c index b68d9f655..ee26cb6cd 100644 --- a/services/std_svc/firme/firme_mecid.c +++ b/services/std_svc/firme/firme_mecid.c @@ -18,7 +18,7 @@ static firme_service_info_t mecid_info = { 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 }, + .feature_reg = { FIRME_MECID_FEAT_REG0_MEC_REFRESH_BIT, 0U }, }; firme_service_info_t *firme_mecid_service_get_info(void) @@ -30,6 +30,23 @@ firme_service_info_t *firme_mecid_service_get_info(void) return &mecid_info; } +int32_t firme_mecid_service_init(void) +{ + uint64_t __maybe_unused mecid_width; + + if (is_feat_mec_supported()) { + mecid_width = (uint64_t)plat_firme_get_common_mecid_width(); + if ((mecid_width & + ~FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_MASK) != 0U) { + return FIRME_INVALID_PARAMETERS; + } + + mecid_info.feature_reg[1] = EXTRACT(FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS, mecid_width); + } + + return 0; +} + static int firme_mec_refresh(u_register_t mec_params) { uint64_t common_mecid_width; @@ -46,8 +63,8 @@ static int firme_mec_refresh(u_register_t mec_params) /* * 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; + common_mecid_width = (mecid_info.feature_reg[1] & + FIRME_MECID_FEAT_REG1_COMMON_MECID_WIDTH_BITS_MASK) + 1U; mecid = EXTRACT(MEC_PARAM_MECID, mec_params); if (mecid > common_mecid_width) { diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c index c2b953fc2..fb402cc6e 100644 --- a/services/std_svc/std_svc_setup.c +++ b/services/std_svc/std_svc_setup.c @@ -83,6 +83,12 @@ static int32_t std_svc_setup(void) trng_setup(); #endif /* TRNG_SUPPORT */ +#if FIRME_SUPPORT + if (firme_init() != 0) { + ret = 1; + } +#endif /* FIRME_SUPPORT */ + #if DRTM_SUPPORT if (drtm_setup() != 0) { ret = 1; |
