@@ -781,6 +781,9 @@ static bool pan3_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
781
781
if (!kvm_has_feat (vcpu -> kvm , ID_AA64MMFR1_EL1 , PAN , PAN3 ))
782
782
return false;
783
783
784
+ if (s1pie_enabled (vcpu , regime ))
785
+ return true;
786
+
784
787
if (regime == TR_EL10 )
785
788
sctlr = vcpu_read_sys_reg (vcpu , SCTLR_EL1 );
786
789
else
@@ -862,11 +865,123 @@ static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu,
862
865
}
863
866
}
864
867
868
+ #define perm_idx (v , r , i ) ((vcpu_read_sys_reg((v), (r)) >> ((i) * 4)) & 0xf)
869
+
870
+ #define set_priv_perms (wr , r , w , x ) \
871
+ do { \
872
+ (wr)->pr = (r); \
873
+ (wr)->pw = (w); \
874
+ (wr)->px = (x); \
875
+ } while (0)
876
+
877
+ #define set_unpriv_perms (wr , r , w , x ) \
878
+ do { \
879
+ (wr)->ur = (r); \
880
+ (wr)->uw = (w); \
881
+ (wr)->ux = (x); \
882
+ } while (0)
883
+
884
+ /* Similar to AArch64.S1IndirectBasePermissions(), without GCS */
885
+ #define set_perms (w , wr , ip ) \
886
+ do { \
887
+ /* R_LLZDZ */ \
888
+ switch ((ip)) { \
889
+ case 0b0000: \
890
+ set_ ## w ## _perms((wr), false, false, false); \
891
+ break; \
892
+ case 0b0001: \
893
+ set_ ## w ## _perms((wr), true , false, false); \
894
+ break; \
895
+ case 0b0010: \
896
+ set_ ## w ## _perms((wr), false, false, true ); \
897
+ break; \
898
+ case 0b0011: \
899
+ set_ ## w ## _perms((wr), true , false, true ); \
900
+ break; \
901
+ case 0b0100: \
902
+ set_ ## w ## _perms((wr), false, false, false); \
903
+ break; \
904
+ case 0b0101: \
905
+ set_ ## w ## _perms((wr), true , true , false); \
906
+ break; \
907
+ case 0b0110: \
908
+ set_ ## w ## _perms((wr), true , true , true ); \
909
+ break; \
910
+ case 0b0111: \
911
+ set_ ## w ## _perms((wr), true , true , true ); \
912
+ break; \
913
+ case 0b1000: \
914
+ set_ ## w ## _perms((wr), true , false, false); \
915
+ break; \
916
+ case 0b1001: \
917
+ set_ ## w ## _perms((wr), true , false, false); \
918
+ break; \
919
+ case 0b1010: \
920
+ set_ ## w ## _perms((wr), true , false, true ); \
921
+ break; \
922
+ case 0b1011: \
923
+ set_ ## w ## _perms((wr), false, false, false); \
924
+ break; \
925
+ case 0b1100: \
926
+ set_ ## w ## _perms((wr), true , true , false); \
927
+ break; \
928
+ case 0b1101: \
929
+ set_ ## w ## _perms((wr), false, false, false); \
930
+ break; \
931
+ case 0b1110: \
932
+ set_ ## w ## _perms((wr), true , true , true ); \
933
+ break; \
934
+ case 0b1111: \
935
+ set_ ## w ## _perms((wr), false, false, false); \
936
+ break; \
937
+ } \
938
+ } while (0)
939
+
940
+ static void compute_s1_indirect_permissions (struct kvm_vcpu * vcpu ,
941
+ struct s1_walk_info * wi ,
942
+ struct s1_walk_result * wr )
943
+ {
944
+ u8 up , pp , idx ;
945
+
946
+ idx = pte_pi_index (wr -> desc );
947
+
948
+ switch (wi -> regime ) {
949
+ case TR_EL10 :
950
+ pp = perm_idx (vcpu , PIR_EL1 , idx );
951
+ up = perm_idx (vcpu , PIRE0_EL1 , idx );
952
+ break ;
953
+ case TR_EL20 :
954
+ pp = perm_idx (vcpu , PIR_EL2 , idx );
955
+ up = perm_idx (vcpu , PIRE0_EL2 , idx );
956
+ break ;
957
+ case TR_EL2 :
958
+ pp = perm_idx (vcpu , PIR_EL2 , idx );
959
+ up = 0 ;
960
+ break ;
961
+ }
962
+
963
+ set_perms (priv , wr , pp );
964
+
965
+ if (wi -> regime != TR_EL2 )
966
+ set_perms (unpriv , wr , up );
967
+ else
968
+ set_unpriv_perms (wr , false, false, false);
969
+
970
+ /* R_VFPJF */
971
+ if (wr -> px && wr -> uw ) {
972
+ set_priv_perms (wr , false, false, false);
973
+ set_unpriv_perms (wr , false, false, false);
974
+ }
975
+ }
976
+
865
977
static void compute_s1_permissions (struct kvm_vcpu * vcpu , u32 op ,
866
978
struct s1_walk_info * wi ,
867
979
struct s1_walk_result * wr )
868
980
{
869
- compute_s1_direct_permissions (vcpu , wi , wr );
981
+ if (!s1pie_enabled (vcpu , wi -> regime ))
982
+ compute_s1_direct_permissions (vcpu , wi , wr );
983
+ else
984
+ compute_s1_indirect_permissions (vcpu , wi , wr );
870
985
871
986
if (!wi -> hpd )
872
987
compute_s1_hierarchical_permissions (vcpu , wi , wr );
0 commit comments