Skip to content

Commit 364c081

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: Implement AT S1PIE support
It doesn't take much effort to implement S1PIE support in AT. It is only a matter of using the AArch64.S1IndirectBasePermissions() encodings for the permission, ignoring GCS which has no impact on AT, and enforce FEAT_PAN3 being enabled as this is a requirement of FEAT_S1PIE. Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Joey Gouly <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 5e21b29 commit 364c081

File tree

1 file changed

+116
-1
lines changed

1 file changed

+116
-1
lines changed

arch/arm64/kvm/at.c

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
865977
static 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

Comments
 (0)