Skip to content

Commit c9c0126

Browse files
Sebastian Eneoupton
authored andcommitted
KVM: arm64: Trap FFA_VERSION host call in pKVM
The pKVM hypervisor initializes with FF-A version 1.0. The spec requires that no other FF-A calls to be issued before the version negotiation phase is complete. Split the hypervisor proxy initialization code in two parts so that we can move the later one after the host negotiates its version. Without trapping the call, the host drivers can negotiate a higher version number with TEE which can result in a different memory layout described during the memory sharing calls. Signed-off-by: Sebastian Ene <[email protected]> Reviewed-by: Sudeep Holla <[email protected]> Tested-by: Sudeep Holla <[email protected]> Acked-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 83a7eef commit c9c0126

File tree

1 file changed

+90
-30
lines changed
  • arch/arm64/kvm/hyp/nvhe

1 file changed

+90
-30
lines changed

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

Lines changed: 90 additions & 30 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
{
@@ -639,6 +642,83 @@ 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+
642722
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
643723
{
644724
struct arm_smccc_res res;
@@ -659,6 +739,11 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
659739
if (!is_ffa_call(func_id))
660740
return false;
661741

742+
if (!has_version_negotiated && func_id != FFA_VERSION) {
743+
ffa_to_smccc_error(&res, FFA_RET_INVALID_PARAMETERS);
744+
goto out_handled;
745+
}
746+
662747
switch (func_id) {
663748
case FFA_FEATURES:
664749
if (!do_ffa_features(&res, host_ctxt))
@@ -685,6 +770,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
685770
case FFA_MEM_FRAG_TX:
686771
do_ffa_mem_frag_tx(&res, host_ctxt);
687772
goto out_handled;
773+
case FFA_VERSION:
774+
do_ffa_version(&res, host_ctxt);
775+
goto out_handled;
688776
}
689777

690778
if (ffa_call_supported(func_id))
@@ -699,7 +787,6 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
699787
int hyp_ffa_init(void *pages)
700788
{
701789
struct arm_smccc_res res;
702-
size_t min_rxtx_sz;
703790
void *tx, *rx;
704791

705792
if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2)
@@ -725,35 +812,7 @@ int hyp_ffa_init(void *pages)
725812
if (FFA_MAJOR_VERSION(res.a0) != 1)
726813
return -EOPNOTSUPP;
727814

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;
756-
815+
hyp_ffa_version = FFA_VERSION_1_0;
757816
tx = pages;
758817
pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE;
759818
rx = pages;
@@ -775,5 +834,6 @@ int hyp_ffa_init(void *pages)
775834
.lock = __HYP_SPIN_LOCK_UNLOCKED,
776835
};
777836

837+
version_lock = __HYP_SPIN_LOCK_UNLOCKED;
778838
return 0;
779839
}

0 commit comments

Comments
 (0)