@@ -781,6 +781,9 @@ static bool pan3_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
781781 if (!kvm_has_feat (vcpu -> kvm , ID_AA64MMFR1_EL1 , PAN , PAN3 ))
782782 return false;
783783
784+ if (s1pie_enabled (vcpu , regime ))
785+ return true;
786+
784787 if (regime == TR_EL10 )
785788 sctlr = vcpu_read_sys_reg (vcpu , SCTLR_EL1 );
786789 else
@@ -862,11 +865,123 @@ static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu,
862865 }
863866}
864867
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+
865977static void compute_s1_permissions (struct kvm_vcpu * vcpu , u32 op ,
866978 struct s1_walk_info * wi ,
867979 struct s1_walk_result * wr )
868980{
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 );
870985
871986 if (!wi -> hpd )
872987 compute_s1_hierarchical_permissions (vcpu , wi , wr );
0 commit comments