mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
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 <maz@kernel.org> Reviewed-by: Joey Gouly <joey.gouly@arm.com> Link: https://lore.kernel.org/r/20241023145345.1613824-22-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
parent
5e21b29787
commit
364c081029
|
|
@ -781,6 +781,9 @@ static bool pan3_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
|
|||
if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, PAN, PAN3))
|
||||
return false;
|
||||
|
||||
if (s1pie_enabled(vcpu, regime))
|
||||
return true;
|
||||
|
||||
if (regime == TR_EL10)
|
||||
sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
|
||||
else
|
||||
|
|
@ -862,11 +865,123 @@ static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
}
|
||||
|
||||
#define perm_idx(v, r, i) ((vcpu_read_sys_reg((v), (r)) >> ((i) * 4)) & 0xf)
|
||||
|
||||
#define set_priv_perms(wr, r, w, x) \
|
||||
do { \
|
||||
(wr)->pr = (r); \
|
||||
(wr)->pw = (w); \
|
||||
(wr)->px = (x); \
|
||||
} while (0)
|
||||
|
||||
#define set_unpriv_perms(wr, r, w, x) \
|
||||
do { \
|
||||
(wr)->ur = (r); \
|
||||
(wr)->uw = (w); \
|
||||
(wr)->ux = (x); \
|
||||
} while (0)
|
||||
|
||||
/* Similar to AArch64.S1IndirectBasePermissions(), without GCS */
|
||||
#define set_perms(w, wr, ip) \
|
||||
do { \
|
||||
/* R_LLZDZ */ \
|
||||
switch ((ip)) { \
|
||||
case 0b0000: \
|
||||
set_ ## w ## _perms((wr), false, false, false); \
|
||||
break; \
|
||||
case 0b0001: \
|
||||
set_ ## w ## _perms((wr), true , false, false); \
|
||||
break; \
|
||||
case 0b0010: \
|
||||
set_ ## w ## _perms((wr), false, false, true ); \
|
||||
break; \
|
||||
case 0b0011: \
|
||||
set_ ## w ## _perms((wr), true , false, true ); \
|
||||
break; \
|
||||
case 0b0100: \
|
||||
set_ ## w ## _perms((wr), false, false, false); \
|
||||
break; \
|
||||
case 0b0101: \
|
||||
set_ ## w ## _perms((wr), true , true , false); \
|
||||
break; \
|
||||
case 0b0110: \
|
||||
set_ ## w ## _perms((wr), true , true , true ); \
|
||||
break; \
|
||||
case 0b0111: \
|
||||
set_ ## w ## _perms((wr), true , true , true ); \
|
||||
break; \
|
||||
case 0b1000: \
|
||||
set_ ## w ## _perms((wr), true , false, false); \
|
||||
break; \
|
||||
case 0b1001: \
|
||||
set_ ## w ## _perms((wr), true , false, false); \
|
||||
break; \
|
||||
case 0b1010: \
|
||||
set_ ## w ## _perms((wr), true , false, true ); \
|
||||
break; \
|
||||
case 0b1011: \
|
||||
set_ ## w ## _perms((wr), false, false, false); \
|
||||
break; \
|
||||
case 0b1100: \
|
||||
set_ ## w ## _perms((wr), true , true , false); \
|
||||
break; \
|
||||
case 0b1101: \
|
||||
set_ ## w ## _perms((wr), false, false, false); \
|
||||
break; \
|
||||
case 0b1110: \
|
||||
set_ ## w ## _perms((wr), true , true , true ); \
|
||||
break; \
|
||||
case 0b1111: \
|
||||
set_ ## w ## _perms((wr), false, false, false); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void compute_s1_indirect_permissions(struct kvm_vcpu *vcpu,
|
||||
struct s1_walk_info *wi,
|
||||
struct s1_walk_result *wr)
|
||||
{
|
||||
u8 up, pp, idx;
|
||||
|
||||
idx = pte_pi_index(wr->desc);
|
||||
|
||||
switch (wi->regime) {
|
||||
case TR_EL10:
|
||||
pp = perm_idx(vcpu, PIR_EL1, idx);
|
||||
up = perm_idx(vcpu, PIRE0_EL1, idx);
|
||||
break;
|
||||
case TR_EL20:
|
||||
pp = perm_idx(vcpu, PIR_EL2, idx);
|
||||
up = perm_idx(vcpu, PIRE0_EL2, idx);
|
||||
break;
|
||||
case TR_EL2:
|
||||
pp = perm_idx(vcpu, PIR_EL2, idx);
|
||||
up = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
set_perms(priv, wr, pp);
|
||||
|
||||
if (wi->regime != TR_EL2)
|
||||
set_perms(unpriv, wr, up);
|
||||
else
|
||||
set_unpriv_perms(wr, false, false, false);
|
||||
|
||||
/* R_VFPJF */
|
||||
if (wr->px && wr->uw) {
|
||||
set_priv_perms(wr, false, false, false);
|
||||
set_unpriv_perms(wr, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_s1_permissions(struct kvm_vcpu *vcpu, u32 op,
|
||||
struct s1_walk_info *wi,
|
||||
struct s1_walk_result *wr)
|
||||
{
|
||||
compute_s1_direct_permissions(vcpu, wi, wr);
|
||||
if (!s1pie_enabled(vcpu, wi->regime))
|
||||
compute_s1_direct_permissions(vcpu, wi, wr);
|
||||
else
|
||||
compute_s1_indirect_permissions(vcpu, wi, wr);
|
||||
|
||||
if (!wi->hpd)
|
||||
compute_s1_hierarchical_permissions(vcpu, wi, wr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user