mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-19 12:25:40 -05:00
KVM: arm64: Allow use of S1 PTW for non-NV vcpus
As we are about to use the S1 PTW in non-NV contexts, we must make sure that we don't evaluate the EL2 state when dealing with the EL1&0 translation regime. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
@@ -98,21 +98,26 @@ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 o
|
||||
}
|
||||
}
|
||||
|
||||
static u64 effective_tcr2(struct kvm_vcpu *vcpu, enum trans_regime regime)
|
||||
{
|
||||
if (regime == TR_EL10) {
|
||||
if (vcpu_has_nv(vcpu) &&
|
||||
!(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En))
|
||||
return 0;
|
||||
|
||||
return __vcpu_sys_reg(vcpu, TCR2_EL1);
|
||||
}
|
||||
|
||||
return vcpu_read_sys_reg(vcpu, TCR2_EL2);
|
||||
}
|
||||
|
||||
static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
|
||||
{
|
||||
if (!kvm_has_s1pie(vcpu->kvm))
|
||||
return false;
|
||||
|
||||
switch (regime) {
|
||||
case TR_EL2:
|
||||
case TR_EL20:
|
||||
return vcpu_read_sys_reg(vcpu, TCR2_EL2) & TCR2_EL2_PIE;
|
||||
case TR_EL10:
|
||||
return (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) &&
|
||||
(__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1_PIE);
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
/* Abuse TCR2_EL1_PIE and use it for EL2 as well */
|
||||
return effective_tcr2(vcpu, regime) & TCR2_EL1_PIE;
|
||||
}
|
||||
|
||||
static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
|
||||
@@ -124,23 +129,11 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (wi->regime) {
|
||||
case TR_EL2:
|
||||
case TR_EL20:
|
||||
val = vcpu_read_sys_reg(vcpu, TCR2_EL2);
|
||||
wi->poe = val & TCR2_EL2_POE;
|
||||
wi->e0poe = (wi->regime == TR_EL20) && (val & TCR2_EL2_E0POE);
|
||||
break;
|
||||
case TR_EL10:
|
||||
if (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) {
|
||||
wi->poe = wi->e0poe = false;
|
||||
return;
|
||||
}
|
||||
val = effective_tcr2(vcpu, wi->regime);
|
||||
|
||||
val = __vcpu_sys_reg(vcpu, TCR2_EL1);
|
||||
wi->poe = val & TCR2_EL1_POE;
|
||||
wi->e0poe = val & TCR2_EL1_E0POE;
|
||||
}
|
||||
/* Abuse TCR2_EL1_* for EL2 */
|
||||
wi->poe = val & TCR2_EL1_POE;
|
||||
wi->e0poe = (wi->regime != TR_EL2) && (val & TCR2_EL1_E0POE);
|
||||
}
|
||||
|
||||
static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
@@ -150,11 +143,16 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
unsigned int stride, x;
|
||||
bool va55, tbi, lva;
|
||||
|
||||
hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
|
||||
|
||||
va55 = va & BIT(55);
|
||||
|
||||
wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC));
|
||||
if (vcpu_has_nv(vcpu)) {
|
||||
hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
|
||||
wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC));
|
||||
} else {
|
||||
WARN_ON_ONCE(wi->regime != TR_EL10);
|
||||
wi->s2 = false;
|
||||
hcr = 0;
|
||||
}
|
||||
|
||||
switch (wi->regime) {
|
||||
case TR_EL10:
|
||||
@@ -851,7 +849,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
par = SYS_PAR_EL1_NSE;
|
||||
par |= wr->pa & SYS_PAR_EL1_PA;
|
||||
|
||||
if (wi->regime == TR_EL10 &&
|
||||
if (wi->regime == TR_EL10 && vcpu_has_nv(vcpu) &&
|
||||
(__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_DC)) {
|
||||
par |= FIELD_PREP(SYS_PAR_EL1_ATTR,
|
||||
MEMATTR(WbRaWa, WbRaWa));
|
||||
|
||||
Reference in New Issue
Block a user