virt inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/10066 ---------------------------------------- The TLBID feature bit in ID_AA64MMFR4_EL1 is only advertised to the guest after userspace configures vDomains via KVM_ARM_VCPU_SET_VDOMAIN, which sets the guest_tlbid_enabled flag. Until then the bit is masked to prevent the guest from enabling TLBID without a valid vDomain affinity. Wire up the logic across three places: - In __kvm_read_sanitised_id_reg() (sys_regs.c): mask TLBID when !vdomain->guest_tlbid_enabled. - In kvm_update_aa64mmfr4_tlbid() (sys_regs.c): write the TLBID field into the VM-wide ID register mirror on the first VCPU_SET_VDOMAIN call, before any vCPU has run. - In kvm_arm_vcpu_set_vdomain() (arm.c): call kvm_update_aa64mmfr4_tlbid() after accepting a valid vDomain configuration. Also declare KVM_REG_ARM_ID_AA64MMFR4_EL1 in the arm64 UAPI header so userspace can read the sanitised register value via KVM_GET_ONE_REG. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> Signed-off-by: Tian Zheng <zhengtian10@huawei.com> --- arch/arm64/include/uapi/asm/kvm.h | 2 ++ arch/arm64/kvm/arm.c | 3 ++ arch/arm64/kvm/sys_regs.c | 50 ++++++++++++++++++++++++++++++- arch/arm64/kvm/sys_regs.h | 6 ++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 93de3f019e5b..99c0e43c43dd 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -253,6 +253,8 @@ struct kvm_arm_counter_offset { #define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64) +#define KVM_REG_ARM_ID_AA64MMFR4_EL1 ARM64_SYS_REG(3, 0, 0, 7, 4) + /* Physical Timer EL0 Registers */ #define KVM_REG_ARM_PTIMER_CTL ARM64_SYS_REG(3, 3, 14, 2, 1) #define KVM_REG_ARM_PTIMER_CVAL ARM64_SYS_REG(3, 3, 14, 2, 2) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 472687b4f536..c87a912c5d03 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -51,6 +51,7 @@ static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT; #include "hisilicon/hisi_virt.h" +#include "sys_regs.h" DEFINE_STATIC_KEY_FALSE(kvm_rme_is_available); @@ -2349,6 +2350,8 @@ static int kvm_arm_vcpu_set_vdomain(struct kvm_vcpu *vcpu, kvm_info("vCPU%d: vDomain bitmap: 0x%x\n", vcpu->vcpu_idx, vdomain_bitmap); + kvm_update_aa64mmfr4_tlbid(vcpu->kvm); + return 0; } #else diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 160c1b57f2c4..7a4e42d2a754 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1470,6 +1470,18 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val &= ID_AA64MMFR3_EL1_TCRX | ID_AA64MMFR3_EL1_S1POE | ID_AA64MMFR3_EL1_S1PIE; break; + case SYS_ID_AA64MMFR4_EL1: + { +#ifdef CONFIG_KVM_ARM_VTLBID + struct tlbidomain *vdomain = &vcpu->kvm->arch.tlbidomain; + + if (!vdomain->guest_tlbid_enabled) + val &= ~ID_AA64MMFR4_EL1_TLBID; +#else + val &= ~ID_AA64MMFR4_EL1_TLBID; +#endif + break; + } case SYS_ID_MMFR4_EL1: val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX); break; @@ -2577,7 +2589,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_WRITABLE(ID_AA64MMFR3_EL1, (ID_AA64MMFR3_EL1_TCRX | ID_AA64MMFR3_EL1_S1PIE | ID_AA64MMFR3_EL1_S1POE)), - ID_UNALLOCATED(7,4), + ID_WRITABLE(ID_AA64MMFR4_EL1, ID_AA64MMFR4_EL1_TLBID_MASK), ID_UNALLOCATED(7,5), ID_UNALLOCATED(7,6), ID_UNALLOCATED(7,7), @@ -3797,6 +3809,42 @@ const struct sys_reg_desc *get_reg_by_id(u64 id, return find_reg(¶ms, table, num); } +/* + * Update the VM's stored value for an ID register. + */ +#ifdef CONFIG_KVM_ARM_VTLBID +void kvm_update_aa64mmfr4_tlbid(struct kvm *kvm) +{ + struct tlbidomain *vdomain = &kvm->arch.tlbidomain; + u64 val, tlbid_val; + + mutex_lock(&kvm->arch.config_lock); + + if (kvm_vm_has_ran_once(kvm)) { + /* + * ID_AA64MMFR4 is a VM-level register already set during + * the first vCPU init. Skip the write to avoid triggering + * KVM_BUG_ON in kvm_set_vm_id_reg(). The per-vCPU + * vdomain_bitmap is still updated by the caller. + */ + mutex_unlock(&kvm->arch.config_lock); + return; + } + + val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1); + tlbid_val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR4_EL1); + tlbid_val &= ID_AA64MMFR4_EL1_TLBID_MASK; + + val &= ~ID_AA64MMFR4_EL1_TLBID_MASK; + if (vdomain->guest_tlbid_enabled) + val |= tlbid_val; + + kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1, val); + + mutex_unlock(&kvm->arch.config_lock); +} +#endif + /* Decode an index value, and find the sys_reg_desc entry. */ static const struct sys_reg_desc * id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 3080693719d2..8a2415921ba0 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -238,6 +238,12 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num); +#ifdef CONFIG_KVM_ARM_VTLBID +void kvm_update_aa64mmfr4_tlbid(struct kvm *kvm); +#else +static inline void kvm_update_aa64mmfr4_tlbid(struct kvm *kvm) { } +#endif + #define AA32(_x) .aarch32_map = AA32_##_x #define Op0(_x) .Op0 = _x #define Op1(_x) .Op1 = _x -- 2.33.0