virt inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10066 ---------------------------------------- Guest-visible TLBIDIDR_EL1 must reflect virtual domain geometry rather than the physical one, because the guest only sees vDomains. Compute a synthesized tlbididr_val at init time that remaps the NVIS and NVOS field values into the NIS and NOS bit positions. Add an access handler (access_tlbididr) that returns this synthesized value on read and silently drops writes, making the register appear invariant to the guest. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> Signed-off-by: Tian Zheng <zhengtian10@huawei.com> --- arch/arm64/kvm/arm.c | 7 +++++++ arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index cfd0f90ec915..472687b4f536 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -336,6 +336,13 @@ static int kvm_arm_init_tlbidomain(struct kvm *kvm) vdomain->nvis = min_t(u8, FIELD_GET(TLBIDIDR_EL1_NVIS_MASK, tlbididr), KVM_VTLBID_MAX_NVIS); vdomain->num_domains = -1; + /* + * Guest-visible TLBIDIDR: the NIS/NOS fields carry the virtual + * domain counts (NVIS/NVOS), since the guest uses vDomains. + */ + vdomain->tlbididr_val = FIELD_PREP(TLBIDIDR_EL1_NIS_MASK, vdomain->nvis) | + FIELD_PREP(TLBIDIDR_EL1_NOS_MASK, + FIELD_GET(TLBIDIDR_EL1_NVOS_MASK, tlbididr)); max_vdomains = 1 << vdomain->nvis; kvm_info("TLBIDIDR: 0x%llx, NIS: %d, NVIS: %d\n", tlbididr, vdomain->nis, vdomain->nvis); diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index fc2a1bc3c314..160c1b57f2c4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -276,6 +276,31 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, return true; } +#ifdef CONFIG_KVM_ARM_VTLBID +static bool access_tlbididr(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + struct tlbidomain *vdomain = &vcpu->kvm->arch.tlbidomain; + + if (p->is_write) + return ignore_write(vcpu, p); + + if (!vdomain->kvm_tlbid_enabled) + return false; + + p->regval = vdomain->tlbididr_val; + return true; +} +#else +static bool access_tlbididr(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + return false; +} +#endif + static bool access_actlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -2633,6 +2658,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_LORN_EL1), trap_loregion }, { SYS_DESC(SYS_LORC_EL1), trap_loregion }, { SYS_DESC(SYS_MPAMIDR_EL1), workaround_bad_mpam_abi }, + { SYS_DESC(SYS_TLBIDIDR_EL1), access_tlbididr }, { SYS_DESC(SYS_LORID_EL1), trap_loregion }, { SYS_DESC(SYS_MPAM1_EL1), workaround_bad_mpam_abi }, -- 2.33.0