@@ -72,7 +72,10 @@
#include "ffa_private.h"
/* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */
-static uint32_t __ro_after_init ffa_fw_version;
+uint32_t __ro_after_init ffa_fw_version;
+
+/* Features supported by the SPMC or secure world when present */
+DECLARE_BITMAP(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE);
struct ffa_fw_abi {
uint32_t id;
@@ -177,6 +180,13 @@ static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid)
else
mask = GENMASK_ULL(31, 0);
+ if ( !ffa_fw_supports_fid(fid) )
+ {
+ resp.a0 = FFA_ERROR;
+ resp.a2 = FFA_RET_NOT_SUPPORTED;
+ goto out;
+ }
+
src_dst = get_user_reg(regs, 1);
if ( (src_dst >> 16) != ffa_get_vm_id(d) )
{
@@ -577,19 +587,16 @@ static bool ffa_probe(void)
else
ffa_fw_version = vers;
- /*
- * At the moment domains must support the same features used by Xen.
- * TODO: Rework the code to allow domain to use a subset of the
- * features supported.
- */
for ( unsigned int i = 0; i < ARRAY_SIZE(ffa_fw_abi_needed); i++ )
{
- if ( !ffa_abi_supported(ffa_fw_abi_needed[i].id) )
- {
+ ASSERT(FFA_ABI_BITNUM(ffa_fw_abi_needed[i].id) < FFA_ABI_BITMAP_SIZE);
+
+ if ( ffa_abi_supported(ffa_fw_abi_needed[i].id) )
+ set_bit(FFA_ABI_BITNUM(ffa_fw_abi_needed[i].id),
+ ffa_fw_abi_supported);
+ else
printk(XENLOG_INFO "ARM FF-A Firmware does not support %s\n",
ffa_fw_abi_needed[i].name);
- goto err_no_fw;
- }
}
if ( !ffa_rxtx_init() )
@@ -611,6 +618,7 @@ err_rxtx_destroy:
ffa_rxtx_destroy();
err_no_fw:
ffa_fw_version = 0;
+ bitmap_zero(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE);
printk(XENLOG_WARNING "ARM FF-A No firmware support\n");
return false;
@@ -377,6 +377,13 @@ void ffa_notif_init(void)
unsigned int irq;
int ret;
+ /* Only enable fw notification if all ABIs we need are supported */
+ if ( !(ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_CREATE) &&
+ ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_DESTROY) &&
+ ffa_fw_supports_fid(FFA_NOTIFICATION_GET) &&
+ ffa_fw_supports_fid(FFA_NOTIFICATION_INFO_GET_64)) )
+ return;
+
arm_smccc_1_2_smc(&arg, &resp);
if ( resp.a0 != FFA_SUCCESS_32 )
return;
@@ -77,7 +77,15 @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
*/
if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG &&
ctx->guest_vers == FFA_VERSION_1_1 )
- return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size);
+ {
+ if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) )
+ return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size);
+ else
+ {
+ *count = 0;
+ return FFA_RET_OK;
+ }
+ }
if ( w5 )
return FFA_RET_INVALID_PARAMETERS;
@@ -87,6 +95,18 @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3,
if ( !spin_trylock(&ctx->rx_lock) )
return FFA_RET_BUSY;
+ if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) )
+ {
+ if ( ctx->guest_vers == FFA_VERSION_1_0 )
+ *fpi_size = sizeof(struct ffa_partition_info_1_0);
+ else
+ *fpi_size = sizeof(struct ffa_partition_info_1_1);
+
+ *count = 0;
+ ret = FFA_RET_OK;
+ goto out;
+ }
+
if ( !ctx->page_count || !ctx->rx_is_free )
goto out;
spin_lock(&ffa_rx_buffer_lock);
@@ -250,6 +270,11 @@ bool ffa_partinfo_init(void)
uint32_t count;
int e;
+ if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ||
+ !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) ||
+ !ffa_rx || !ffa_tx )
+ return false;
+
e = ffa_partition_info_get(0, 0, 0, 0, 0, &count, &fpi_size);
if ( e )
{
@@ -313,6 +338,9 @@ int ffa_partinfo_domain_init(struct domain *d)
unsigned int n;
int32_t res;
+ if ( !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) )
+ return 0;
+
ctx->vm_destroy_bitmap = xzalloc_array(unsigned long, count);
if ( !ctx->vm_destroy_bitmap )
return -ENOMEM;
@@ -14,6 +14,7 @@
#include <xen/spinlock.h>
#include <xen/sched.h>
#include <xen/time.h>
+#include <xen/bitmap.h>
/* Error codes */
#define FFA_RET_OK 0
@@ -201,18 +202,17 @@
#define FFA_INTERRUPT 0x84000062U
#define FFA_VERSION 0x84000063U
#define FFA_FEATURES 0x84000064U
-#define FFA_RX_ACQUIRE 0x84000084U
#define FFA_RX_RELEASE 0x84000065U
#define FFA_RXTX_MAP_32 0x84000066U
#define FFA_RXTX_MAP_64 0xC4000066U
#define FFA_RXTX_UNMAP 0x84000067U
#define FFA_PARTITION_INFO_GET 0x84000068U
#define FFA_ID_GET 0x84000069U
-#define FFA_SPM_ID_GET 0x84000085U
+#define FFA_MSG_POLL 0x8400006AU
#define FFA_MSG_WAIT 0x8400006BU
#define FFA_MSG_YIELD 0x8400006CU
#define FFA_RUN 0x8400006DU
-#define FFA_MSG_SEND2 0x84000086U
+#define FFA_MSG_SEND 0x8400006EU
#define FFA_MSG_SEND_DIRECT_REQ_32 0x8400006FU
#define FFA_MSG_SEND_DIRECT_REQ_64 0xC400006FU
#define FFA_MSG_SEND_DIRECT_RESP_32 0x84000070U
@@ -230,8 +230,6 @@
#define FFA_MEM_RECLAIM 0x84000077U
#define FFA_MEM_FRAG_RX 0x8400007AU
#define FFA_MEM_FRAG_TX 0x8400007BU
-#define FFA_MSG_SEND 0x8400006EU
-#define FFA_MSG_POLL 0x8400006AU
#define FFA_NOTIFICATION_BITMAP_CREATE 0x8400007DU
#define FFA_NOTIFICATION_BITMAP_DESTROY 0x8400007EU
#define FFA_NOTIFICATION_BIND 0x8400007FU
@@ -240,6 +238,25 @@
#define FFA_NOTIFICATION_GET 0x84000082U
#define FFA_NOTIFICATION_INFO_GET_32 0x84000083U
#define FFA_NOTIFICATION_INFO_GET_64 0xC4000083U
+#define FFA_RX_ACQUIRE 0x84000084U
+#define FFA_SPM_ID_GET 0x84000085U
+#define FFA_MSG_SEND2 0x84000086U
+
+/**
+ * Encoding of features supported or not by the fw in a bitmap:
+ * - Function IDs are going from 0x60 to 0xFF
+ * - A function can be supported in 32 and/or 64bit
+ * The bitmap has one bit for each function in 32 and 64 bit.
+ */
+#define FFA_ABI_ID(id) ((id) & ARM_SMCCC_FUNC_MASK)
+#define FFA_ABI_CONV(id) (((id) >> ARM_SMCCC_CONV_SHIFT) & BIT(0,U))
+
+#define FFA_ABI_MIN FFA_ABI_ID(FFA_ERROR)
+#define FFA_ABI_MAX FFA_ABI_ID(FFA_MSG_SEND2)
+
+#define FFA_ABI_BITMAP_SIZE (2 * (FFA_ABI_MAX - FFA_ABI_MIN + 1))
+#define FFA_ABI_BITNUM(id) ((FFA_ABI_ID(id) - FFA_ABI_MIN) << 1 | \
+ FFA_ABI_CONV(id))
struct ffa_ctx_notif {
bool enabled;
@@ -289,6 +306,8 @@ extern void *ffa_rx;
extern void *ffa_tx;
extern spinlock_t ffa_rx_buffer_lock;
extern spinlock_t ffa_tx_buffer_lock;
+extern uint32_t __ro_after_init ffa_fw_version;
+extern DECLARE_BITMAP(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE);
bool ffa_shm_domain_destroy(struct domain *d);
void ffa_handle_mem_share(struct cpu_user_regs *regs);
@@ -401,4 +420,13 @@ static inline int32_t ffa_rx_release(void)
return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0);
}
+static inline bool ffa_fw_supports_fid(uint32_t fid)
+{
+ BUILD_BUG_ON(FFA_ABI_MIN > FFA_ABI_MAX);
+
+ if ( FFA_ABI_BITNUM(fid) > FFA_ABI_BITMAP_SIZE)
+ return false;
+ return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported);
+}
+
#endif /*__FFA_PRIVATE_H__*/
@@ -193,6 +193,10 @@ bool ffa_rxtx_init(void)
{
int e;
+ /* Firmware not there or not supporting */
+ if ( !ffa_fw_supports_fid(FFA_RXTX_MAP_64) )
+ return false;
+
ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0);
if ( !ffa_rx )
return false;
@@ -149,6 +149,9 @@ static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len,
static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi,
uint32_t flags)
{
+ if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) )
+ return FFA_RET_NOT_SUPPORTED;
+
return ffa_simple_call(FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0);
}
@@ -467,6 +470,12 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs)
uint32_t range_count;
uint32_t region_offs;
+ if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) )
+ {
+ ret = FFA_RET_NOT_SUPPORTED;
+ goto out_set_ret;
+ }
+
/*
* We're only accepting memory transaction descriptors via the rx/tx
* buffer.
@@ -621,6 +630,9 @@ int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags)
register_t handle_lo;
int ret;
+ if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) )
+ return FFA_RET_NOT_SUPPORTED;
+
spin_lock(&ctx->lock);
shm = find_shm_mem(ctx, handle);
if ( shm )