Skip to content

Commit a35d5b2

Browse files
committed
Merge branch kvm-arm64/ffa-1p1 into kvmarm/next
* kvm-arm64/ffa-1p1: : Improvements to the pKVM FF-A Proxy, courtesy of Sebastian Ene : : Various minor improvements to how host FF-A calls are proxied with the : TEE, along with support for v1.1 of the protocol. KVM: arm64: Use FF-A 1.1 with pKVM KVM: arm64: Update the identification range for the FF-A smcs KVM: arm64: Add support for FFA_PARTITION_INFO_GET KVM: arm64: Trap FFA_VERSION host call in pKVM Signed-off-by: Oliver Upton <[email protected]>
2 parents bd2e951 + 42fb33d commit a35d5b2

File tree

3 files changed

+152
-33
lines changed

3 files changed

+152
-33
lines changed

arch/arm64/kvm/hyp/include/nvhe/ffa.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <asm/kvm_host.h>
1010

1111
#define FFA_MIN_FUNC_NUM 0x60
12-
#define FFA_MAX_FUNC_NUM 0x7F
12+
#define FFA_MAX_FUNC_NUM 0xFF
1313

1414
int hyp_ffa_init(void *pages);
1515
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id);

arch/arm64/kvm/hyp/nvhe/ffa.c

Lines changed: 148 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ struct kvm_ffa_buffers {
6767
*/
6868
static struct kvm_ffa_buffers hyp_buffers;
6969
static struct kvm_ffa_buffers host_buffers;
70+
static u32 hyp_ffa_version;
71+
static bool has_version_negotiated;
72+
static hyp_spinlock_t version_lock;
7073

7174
static void ffa_to_smccc_error(struct arm_smccc_res *res, u64 ffa_errno)
7275
{
@@ -454,7 +457,7 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
454457
memcpy(buf, host_buffers.tx, fraglen);
455458

456459
ep_mem_access = (void *)buf +
457-
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
460+
ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
458461
offset = ep_mem_access->composite_off;
459462
if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) {
460463
ret = FFA_RET_INVALID_PARAMETERS;
@@ -533,7 +536,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
533536
fraglen = res->a2;
534537

535538
ep_mem_access = (void *)buf +
536-
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
539+
ffa_mem_desc_offset(buf, 0, hyp_ffa_version);
537540
offset = ep_mem_access->composite_off;
538541
/*
539542
* We can trust the SPMD to get this right, but let's at least
@@ -639,6 +642,132 @@ static bool do_ffa_features(struct arm_smccc_res *res,
639642
return true;
640643
}
641644

645+
static int hyp_ffa_post_init(void)
646+
{
647+
size_t min_rxtx_sz;
648+
struct arm_smccc_res res;
649+
650+
arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res);
651+
if (res.a0 != FFA_SUCCESS)
652+
return -EOPNOTSUPP;
653+
654+
if (res.a2 != HOST_FFA_ID)
655+
return -EINVAL;
656+
657+
arm_smccc_1_1_smc(FFA_FEATURES, FFA_FN64_RXTX_MAP,
658+
0, 0, 0, 0, 0, 0, &res);
659+
if (res.a0 != FFA_SUCCESS)
660+
return -EOPNOTSUPP;
661+
662+
switch (res.a2) {
663+
case FFA_FEAT_RXTX_MIN_SZ_4K:
664+
min_rxtx_sz = SZ_4K;
665+
break;
666+
case FFA_FEAT_RXTX_MIN_SZ_16K:
667+
min_rxtx_sz = SZ_16K;
668+
break;
669+
case FFA_FEAT_RXTX_MIN_SZ_64K:
670+
min_rxtx_sz = SZ_64K;
671+
break;
672+
default:
673+
return -EINVAL;
674+
}
675+
676+
if (min_rxtx_sz > PAGE_SIZE)
677+
return -EOPNOTSUPP;
678+
679+
return 0;
680+
}
681+
682+
static void do_ffa_version(struct arm_smccc_res *res,
683+
struct kvm_cpu_context *ctxt)
684+
{
685+
DECLARE_REG(u32, ffa_req_version, ctxt, 1);
686+
687+
if (FFA_MAJOR_VERSION(ffa_req_version) != 1) {
688+
res->a0 = FFA_RET_NOT_SUPPORTED;
689+
return;
690+
}
691+
692+
hyp_spin_lock(&version_lock);
693+
if (has_version_negotiated) {
694+
res->a0 = hyp_ffa_version;
695+
goto unlock;
696+
}
697+
698+
/*
699+
* If the client driver tries to downgrade the version, we need to ask
700+
* first if TEE supports it.
701+
*/
702+
if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) {
703+
arm_smccc_1_1_smc(FFA_VERSION, ffa_req_version, 0,
704+
0, 0, 0, 0, 0,
705+
res);
706+
if (res->a0 == FFA_RET_NOT_SUPPORTED)
707+
goto unlock;
708+
709+
hyp_ffa_version = ffa_req_version;
710+
}
711+
712+
if (hyp_ffa_post_init())
713+
res->a0 = FFA_RET_NOT_SUPPORTED;
714+
else {
715+
has_version_negotiated = true;
716+
res->a0 = hyp_ffa_version;
717+
}
718+
unlock:
719+
hyp_spin_unlock(&version_lock);
720+
}
721+
722+
static void do_ffa_part_get(struct arm_smccc_res *res,
723+
struct kvm_cpu_context *ctxt)
724+
{
725+
DECLARE_REG(u32, uuid0, ctxt, 1);
726+
DECLARE_REG(u32, uuid1, ctxt, 2);
727+
DECLARE_REG(u32, uuid2, ctxt, 3);
728+
DECLARE_REG(u32, uuid3, ctxt, 4);
729+
DECLARE_REG(u32, flags, ctxt, 5);
730+
u32 count, partition_sz, copy_sz;
731+
732+
hyp_spin_lock(&host_buffers.lock);
733+
if (!host_buffers.rx) {
734+
ffa_to_smccc_res(res, FFA_RET_BUSY);
735+
goto out_unlock;
736+
}
737+
738+
arm_smccc_1_1_smc(FFA_PARTITION_INFO_GET, uuid0, uuid1,
739+
uuid2, uuid3, flags, 0, 0,
740+
res);
741+
742+
if (res->a0 != FFA_SUCCESS)
743+
goto out_unlock;
744+
745+
count = res->a2;
746+
if (!count)
747+
goto out_unlock;
748+
749+
if (hyp_ffa_version > FFA_VERSION_1_0) {
750+
/* Get the number of partitions deployed in the system */
751+
if (flags & 0x1)
752+
goto out_unlock;
753+
754+
partition_sz = res->a3;
755+
} else {
756+
/* FFA_VERSION_1_0 lacks the size in the response */
757+
partition_sz = FFA_1_0_PARTITON_INFO_SZ;
758+
}
759+
760+
copy_sz = partition_sz * count;
761+
if (copy_sz > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
762+
ffa_to_smccc_res(res, FFA_RET_ABORTED);
763+
goto out_unlock;
764+
}
765+
766+
memcpy(host_buffers.rx, hyp_buffers.rx, copy_sz);
767+
out_unlock:
768+
hyp_spin_unlock(&host_buffers.lock);
769+
}
770+
642771
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
643772
{
644773
struct arm_smccc_res res;
@@ -659,6 +788,11 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
659788
if (!is_ffa_call(func_id))
660789
return false;
661790

791+
if (!has_version_negotiated && func_id != FFA_VERSION) {
792+
ffa_to_smccc_error(&res, FFA_RET_INVALID_PARAMETERS);
793+
goto out_handled;
794+
}
795+
662796
switch (func_id) {
663797
case FFA_FEATURES:
664798
if (!do_ffa_features(&res, host_ctxt))
@@ -685,6 +819,12 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
685819
case FFA_MEM_FRAG_TX:
686820
do_ffa_mem_frag_tx(&res, host_ctxt);
687821
goto out_handled;
822+
case FFA_VERSION:
823+
do_ffa_version(&res, host_ctxt);
824+
goto out_handled;
825+
case FFA_PARTITION_INFO_GET:
826+
do_ffa_part_get(&res, host_ctxt);
827+
goto out_handled;
688828
}
689829

690830
if (ffa_call_supported(func_id))
@@ -699,13 +839,12 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
699839
int hyp_ffa_init(void *pages)
700840
{
701841
struct arm_smccc_res res;
702-
size_t min_rxtx_sz;
703842
void *tx, *rx;
704843

705844
if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2)
706845
return 0;
707846

708-
arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_0, 0, 0, 0, 0, 0, 0, &res);
847+
arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_1, 0, 0, 0, 0, 0, 0, &res);
709848
if (res.a0 == FFA_RET_NOT_SUPPORTED)
710849
return 0;
711850

@@ -725,34 +864,10 @@ int hyp_ffa_init(void *pages)
725864
if (FFA_MAJOR_VERSION(res.a0) != 1)
726865
return -EOPNOTSUPP;
727866

728-
arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res);
729-
if (res.a0 != FFA_SUCCESS)
730-
return -EOPNOTSUPP;
731-
732-
if (res.a2 != HOST_FFA_ID)
733-
return -EINVAL;
734-
735-
arm_smccc_1_1_smc(FFA_FEATURES, FFA_FN64_RXTX_MAP,
736-
0, 0, 0, 0, 0, 0, &res);
737-
if (res.a0 != FFA_SUCCESS)
738-
return -EOPNOTSUPP;
739-
740-
switch (res.a2) {
741-
case FFA_FEAT_RXTX_MIN_SZ_4K:
742-
min_rxtx_sz = SZ_4K;
743-
break;
744-
case FFA_FEAT_RXTX_MIN_SZ_16K:
745-
min_rxtx_sz = SZ_16K;
746-
break;
747-
case FFA_FEAT_RXTX_MIN_SZ_64K:
748-
min_rxtx_sz = SZ_64K;
749-
break;
750-
default:
751-
return -EINVAL;
752-
}
753-
754-
if (min_rxtx_sz > PAGE_SIZE)
755-
return -EOPNOTSUPP;
867+
if (FFA_MINOR_VERSION(res.a0) < FFA_MINOR_VERSION(FFA_VERSION_1_1))
868+
hyp_ffa_version = res.a0;
869+
else
870+
hyp_ffa_version = FFA_VERSION_1_1;
756871

757872
tx = pages;
758873
pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE;
@@ -775,5 +890,6 @@ int hyp_ffa_init(void *pages)
775890
.lock = __HYP_SPIN_LOCK_UNLOCKED,
776891
};
777892

893+
version_lock = __HYP_SPIN_LOCK_UNLOCKED;
778894
return 0;
779895
}

include/linux/arm_ffa.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; }
212212

213213
extern const struct bus_type ffa_bus_type;
214214

215+
/* The FF-A 1.0 partition structure lacks the uuid[4] */
216+
#define FFA_1_0_PARTITON_INFO_SZ (8)
217+
215218
/* FFA transport related */
216219
struct ffa_partition_info {
217220
u16 id;

0 commit comments

Comments
 (0)