@@ -67,6 +67,9 @@ struct kvm_ffa_buffers {
67
67
*/
68
68
static struct kvm_ffa_buffers hyp_buffers ;
69
69
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 ;
70
73
71
74
static void ffa_to_smccc_error (struct arm_smccc_res * res , u64 ffa_errno )
72
75
{
@@ -454,7 +457,7 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
454
457
memcpy (buf , host_buffers .tx , fraglen );
455
458
456
459
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 );
458
461
offset = ep_mem_access -> composite_off ;
459
462
if (!offset || buf -> ep_count != 1 || buf -> sender_id != HOST_FFA_ID ) {
460
463
ret = FFA_RET_INVALID_PARAMETERS ;
@@ -533,7 +536,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
533
536
fraglen = res -> a2 ;
534
537
535
538
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 );
537
540
offset = ep_mem_access -> composite_off ;
538
541
/*
539
542
* 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,
639
642
return true;
640
643
}
641
644
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
+
642
771
bool kvm_host_ffa_handler (struct kvm_cpu_context * host_ctxt , u32 func_id )
643
772
{
644
773
struct arm_smccc_res res ;
@@ -659,6 +788,11 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
659
788
if (!is_ffa_call (func_id ))
660
789
return false;
661
790
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
+
662
796
switch (func_id ) {
663
797
case FFA_FEATURES :
664
798
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)
685
819
case FFA_MEM_FRAG_TX :
686
820
do_ffa_mem_frag_tx (& res , host_ctxt );
687
821
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 ;
688
828
}
689
829
690
830
if (ffa_call_supported (func_id ))
@@ -699,13 +839,12 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
699
839
int hyp_ffa_init (void * pages )
700
840
{
701
841
struct arm_smccc_res res ;
702
- size_t min_rxtx_sz ;
703
842
void * tx , * rx ;
704
843
705
844
if (kvm_host_psci_config .smccc_version < ARM_SMCCC_VERSION_1_2 )
706
845
return 0 ;
707
846
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 );
709
848
if (res .a0 == FFA_RET_NOT_SUPPORTED )
710
849
return 0 ;
711
850
@@ -725,34 +864,10 @@ int hyp_ffa_init(void *pages)
725
864
if (FFA_MAJOR_VERSION (res .a0 ) != 1 )
726
865
return - EOPNOTSUPP ;
727
866
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 ;
756
871
757
872
tx = pages ;
758
873
pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE ;
@@ -775,5 +890,6 @@ int hyp_ffa_init(void *pages)
775
890
.lock = __HYP_SPIN_LOCK_UNLOCKED ,
776
891
};
777
892
893
+ version_lock = __HYP_SPIN_LOCK_UNLOCKED ;
778
894
return 0 ;
779
895
}
0 commit comments