SPCI: SPCI_FEATURES implementation.
Change-Id: I1bb3e32808d503ee75303a5e70b41645b2d7e86b
diff --git a/inc/hf/api.h b/inc/hf/api.h
index 406b620..024973e 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -66,3 +66,4 @@
struct vm_locked to_locked, struct vm_locked from_locked,
struct spci_memory_region *memory_region, uint32_t memory_to_attributes,
enum spci_memory_share share);
+struct spci_value api_spci_features(uint32_t function_id);
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 9091875..52396aa 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -297,3 +297,19 @@
{
return spci_call((struct spci_value){.func = SPCI_VERSION_32});
}
+
+/**
+ * Discovery function returning information about the implementation of optional
+ * SPCI interfaces.
+ *
+ * Returns:
+ * - SPCI_SUCCESS in .func if the the optional interface with function_id is
+ * implemented.
+ * - SPCI_ERROR in .func if the optional interface with function_id is not
+ * implemented.
+ */
+static inline struct spci_value spci_features(uint32_t function_id)
+{
+ return spci_call((struct spci_value){.func = SPCI_FEATURES_32,
+ .arg1 = function_id});
+}
diff --git a/src/api.c b/src/api.c
index 92328c8..7c1f12a 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1705,3 +1705,25 @@
return 0;
}
+
+/**
+ * Discovery function returning information about the implementation of optional
+ * SPCI interfaces.
+ */
+struct spci_value api_spci_features(uint32_t function_id)
+{
+ switch (function_id) {
+ case SPCI_ERROR_32:
+ case SPCI_SUCCESS_32:
+ case SPCI_ID_GET_32:
+ case SPCI_YIELD_32:
+ case SPCI_VERSION_32:
+ case SPCI_FEATURES_32:
+ case SPCI_MSG_SEND_32:
+ case SPCI_MSG_POLL_32:
+ case SPCI_MSG_WAIT_32:
+ return (struct spci_value){.func = SPCI_SUCCESS_32};
+ default:
+ return spci_error(SPCI_NOT_SUPPORTED);
+ }
+}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index bbb115f..7928f54 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -312,6 +312,10 @@
static bool spci_handler(struct spci_value *args, struct vcpu **next)
{
+ /*
+ * NOTE: When adding new methods to this handler update
+ * api_spci_features accordingly.
+ */
switch (args->func & ~SMCCC_CONVENTION_MASK) {
case SPCI_VERSION_32:
*args = api_spci_version();
@@ -319,6 +323,9 @@
case SPCI_ID_GET_32:
*args = api_spci_id_get(current());
return true;
+ case SPCI_FEATURES_32:
+ *args = api_spci_features(args->arg1);
+ return true;
case SPCI_YIELD_32:
api_yield(current(), next);
diff --git a/test/vmapi/primary_only/primary_only.c b/test/vmapi/primary_only/primary_only.c
index 96b1309..74302c6 100644
--- a/test/vmapi/primary_only/primary_only.c
+++ b/test/vmapi/primary_only/primary_only.c
@@ -158,6 +158,99 @@
EXPECT_EQ(ret.arg2, current_version);
}
+/** Ensures that SPCI_FEATURES is reporting the expected interfaces. */
+TEST(spci, spci_features)
+{
+ struct spci_value ret;
+
+ ret = spci_features(SPCI_ERROR_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_SUCCESS_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_VERSION_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_FEATURES_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_ID_GET_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_YIELD_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_MSG_SEND_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_MSG_POLL_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_MSG_WAIT_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+
+ ret = spci_features(SPCI_YIELD_32);
+ EXPECT_EQ(ret.func, SPCI_SUCCESS_32);
+}
+
+/**
+ * Ensures that SPCI_FEATURES returns not supported for a bogus FID or
+ * currently non-implemented interfaces.
+ */
+TEST(spci, spci_features_not_supported)
+{
+ struct spci_value ret;
+
+ ret = spci_features(0);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(0x84000000);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_INTERRUPT_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_RX_RELEASE_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_RXTX_MAP_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_RXTX_UNMAP_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_PARTITION_INFO_GET_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_RUN_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_MSG_SEND_DIRECT_RESP_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_MSG_SEND_DIRECT_REQ_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_MSG_SEND_DIRECT_REQ_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+
+ ret = spci_features(SPCI_MSG_SEND_DIRECT_RESP_32);
+ EXPECT_EQ(ret.func, SPCI_ERROR_32);
+ EXPECT_EQ(ret.arg2, SPCI_NOT_SUPPORTED);
+}
+
/**
* Test that floating-point operations work in the primary VM.
*/