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. If vTLBID is not enabled for the VM, or the feature is compiled out, the handler injects an UNDEFINED exception into 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 | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e3f00cfefb08..3903a832946e 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..44d25648d19d 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -276,6 +276,34 @@ 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) { + kvm_inject_undefined(vcpu); + 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) +{ + kvm_inject_undefined(vcpu); + return false; +} +#endif + static bool access_actlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -2633,6 +2661,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