feat(smccc): add SoC name support to SMCCC_ARCH_SOC_ID
This patch adds support for getting the SoC name string
using the SMCCC_ARCH_SOC_ID interface. The SoC name query
was introduced in SMCCC version 1.6. It is available only
through SMC64 calls.
A new function ID, SMCCC_GET_SOC_NAME, is added. It returns
the SoC name as a null-terminated ASCII string, spread across
registers X1 to X17 in little endian order.
The total length is 136 bytes, including the null byte.
Any space after the null terminator is filled
with zeros.
A platform hook plat_get_soc_name() is added to return the
SoC name. A weak default version is also provided that returns
SMC_ARCH_CALL_NOT_SUPPORTED for platforms that do not support
this feature.
The name should follow the SMCCC rule that it must not expose
any information that is not already reported
by the SoC version and revision calls.
Reference: https://developer.arm.com/documentation/den0028/latest/
Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
Change-Id: Idc69997c509bcbfb1cecb38ed1003b29627ade4b
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index e37fe1f..81999fc 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1511,6 +1511,23 @@
soc_revision[0:30] = SOC revision of specific SOC
+Function : plat_get_soc_name()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : char **
+ Return : int32_t
+
+The plat_get_soc_name() function allows a platform to expose the SoC name to
+the firmware. It takes a pointer to a character pointer as an argument, which
+must be set to point to a static, null-terminated SoC name string. The string
+must be encoded in UTF-8 and should use only printable ASCII characters for
+compatibility. It must not exceed 136 bytes, including the null terminator. On
+success, the function returns SMC_ARCH_CALL_SUCCESS. If the platform does not
+support SoC name retrieval, it returns SMC_ARCH_CALL_NOT_SUPPORTED. This API
+allows platforms to support SoC name queries via SMCCC_ARCH_SOC_ID.
+
Function : plat_is_smccc_feature_available()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 8c6ee98..d7c5ed9 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -496,6 +496,11 @@
int32_t plat_get_soc_revision(void);
/*
+ * Optional function to get SoC name
+ */
+int32_t plat_get_soc_name(char *soc_name);
+
+/*
* Optional function to check for SMCCC function availability for platform
*/
int32_t plat_is_smccc_feature_available(u_register_t fid);
diff --git a/include/services/arm_arch_svc.h b/include/services/arm_arch_svc.h
index 242bf66..4f5c24b 100644
--- a/include/services/arm_arch_svc.h
+++ b/include/services/arm_arch_svc.h
@@ -18,6 +18,9 @@
#define SMCCC_GET_SOC_VERSION U(0)
#define SMCCC_GET_SOC_REVISION U(1)
+#define SMCCC_GET_SOC_NAME U(2)
+
+#define SMCCC_SOC_NAME_LEN U(136)
#ifndef __ASSEMBLER__
#if ARCH_FEATURE_AVAILABILITY
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
index f10f2d7..990a36a 100644
--- a/plat/common/plat_bl_common.c
+++ b/plat/common/plat_bl_common.c
@@ -31,6 +31,7 @@
#pragma weak plat_is_smccc_feature_available
#pragma weak plat_get_soc_version
#pragma weak plat_get_soc_revision
+#pragma weak plat_get_soc_name
int32_t plat_get_soc_version(void)
{
@@ -42,6 +43,11 @@
return SMC_ARCH_CALL_NOT_SUPPORTED;
}
+int32_t plat_get_soc_name(char *soc_name __unused)
+{
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+}
+
int32_t plat_is_smccc_feature_available(u_register_t fid __unused)
{
return SMC_ARCH_CALL_NOT_SUPPORTED;
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
index 329f59b..00026eb 100644
--- a/services/arm_arch_svc/arm_arch_svc_setup.c
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -121,17 +121,53 @@
}
}
-/* return soc revision or soc version on success otherwise
- * return invalid parameter */
-static int32_t smccc_arch_id(u_register_t arg1)
+/*
+ * Handles SMCCC_ARCH_SOC_ID smc calls.
+ *
+ * - GET_SOC_REVISION: returns SoC revision (AArch32/AArch64)
+ * - GET_SOC_VERSION: returns SoC version (AArch32/AArch64)
+ * - GET_SOC_NAME: returns SoC name string (AArch64 only)
+ *
+ * Returns invalid parameter for unsupported calls.
+ */
+static uintptr_t smccc_arch_id(u_register_t arg1, void *handle, uint32_t is_smc64)
{
if (arg1 == SMCCC_GET_SOC_REVISION) {
- return plat_get_soc_revision();
+ SMC_RET1(handle, plat_get_soc_revision());
}
if (arg1 == SMCCC_GET_SOC_VERSION) {
- return plat_get_soc_version();
+ SMC_RET1(handle, plat_get_soc_version());
}
- return SMC_ARCH_CALL_INVAL_PARAM;
+#if __aarch64__
+ /* SoC Name is only present for SMC64 invocations */
+ if ((arg1 == SMCCC_GET_SOC_NAME) && is_smc64) {
+ uint64_t arg[SMCCC_SOC_NAME_LEN / 8];
+ int32_t ret;
+ char soc_name[SMCCC_SOC_NAME_LEN];
+
+ (void)memset(soc_name, 0U, SMCCC_SOC_NAME_LEN);
+ ret = plat_get_soc_name(soc_name);
+
+ if (ret == SMC_ARCH_CALL_SUCCESS) {
+ (void)memcpy(arg, soc_name, SMCCC_SOC_NAME_LEN);
+ /*
+ * The SoC name is returned as a null-terminated
+ * ASCII string, split across registers X1 to X17
+ * in little endian order.
+ * Each 64-bit register holds 8 consecutive bytes
+ * of the string.
+ */
+ SMC_RET18(handle, ret, arg[0], arg[1], arg[2],
+ arg[3], arg[4], arg[5], arg[6],
+ arg[7], arg[8], arg[9], arg[10],
+ arg[11], arg[12], arg[13], arg[14],
+ arg[15], arg[16]);
+ } else {
+ SMC_RET1(handle, ret);
+ }
+ }
+#endif /* __aarch64__ */
+ SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
}
/*
@@ -237,8 +273,10 @@
case SMCCC_ARCH_FEATURES:
SMC_RET1(handle, smccc_arch_features(x1));
case SMCCC_ARCH_SOC_ID:
- SMC_RET1(handle, smccc_arch_id(x1));
-#ifdef __aarch64__
+ case SMCCC_ARCH_SOC_ID | (SMC_64 << FUNCID_CC_SHIFT):
+ return smccc_arch_id(x1, handle, (smc_fid
+ & (SMC_64 << FUNCID_CC_SHIFT)));
+#if __aarch64__
#if WORKAROUND_CVE_2017_5715
case SMCCC_ARCH_WORKAROUND_1:
/*