virt inclusion category: feature bugzilla: https://gitcode.com/openeuler/kernel/issues/10066 ---------------------------------------- Wrap all virtual TLBID (vTLBID) code in KVM behind a new CONFIG_KVM_ARM_VTLBID Kconfig option (default n, depends on KVM && ARM64_TLBID). When disabled, stub functions provide no-op behaviour so the rest of KVM compiles and runs without vTLBID support. Guards are placed at five sites in arm.c, each wrapping only vTLBID-specific functions so non-vTLBID code is unaffected: - Group A: kvm_tlbidomain(), kvm_arm_init_tlbidomain(), free_tlbid_vdomain() and the tlbid_domains xarray - Group B: is_vcpu_in_vdomain(), update_domain_map(), vtlbidn_clear_set_s(), kvm_arm_update_tlbid_map(), kvm_vcpu_reload_tlbid(), set_tlbididr_trap(), kvm_tlbidomain_vcpu_load(), clear_tlbididr_trap(), kvm_tlbidomain_vcpu_put() - Group C: kvm_arm_tlbidomain_vcpu_init() - Group D: kvm_arm_vcpu_set_vdomain() - Group E: kvm_arm_get_vdomain_num() Cross-file functions (kvm_tlbidomain, kvm_update_aa64mmfr4_tlbid) get inline stubs in their headers; access_tlbididr() in sys_regs.c gets a #else stub returning false. KVM_CAP_ARM_TLBIDOMAIN is additionally gated by IS_ENABLED(CONFIG_KVM_ARM_VTLBID). Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/include/asm/kvm_host.h | 4 ++++ arch/arm64/kvm/Kconfig | 12 +++++++++++ arch/arm64/kvm/arm.c | 33 ++++++++++++++++++++++++++++++- arch/arm64/kvm/sys_regs.c | 11 +++++++++++ arch/arm64/kvm/sys_regs.h | 4 ++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index ed2083b7b206..6ad17d3e9b78 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -257,7 +257,11 @@ struct tlbidomain { * xarray keyed by the kvm pointer so that struct kvm_arch stays unchanged * (no KABI impact). Returns NULL when the VM has no TLBID support. */ +#ifdef CONFIG_KVM_ARM_VTLBID struct tlbidomain *kvm_tlbidomain(struct kvm *kvm); +#else +static inline struct tlbidomain *kvm_tlbidomain(struct kvm *kvm) { return NULL; } +#endif struct kvm_arch { struct kvm_s2_mmu mmu; diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 689d32b140b7..2a71109ce082 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -145,4 +145,16 @@ config VIRT_TIMER_EARLY_INJECT The hypervisor can control the early injection latency via the module parameter: timer_early_inject_ns +config KVM_ARM_VTLBID + bool "Virtual TLBID support for KVM guests" + depends on KVM && ARM64_TLBID + default n + help + Enable virtualization of FEAT_TLBID so that each KVM guest can + use TLBI Domains independently of the host. The host TLBID + hardware is partitioned per-VM through VTLBID_EL2 registers + managed on the vCPU load/put path. + + If unsure, say N. + endif # VIRTUALIZATION diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 0025b0499211..d641b0dc1d6c 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -321,6 +321,7 @@ static int kvm_arm_default_max_vcpus(void) return vgic_present ? kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS; } +#ifdef CONFIG_KVM_ARM_VTLBID static DEFINE_XARRAY(tlbid_domains); struct tlbidomain *kvm_tlbidomain(struct kvm *kvm) @@ -435,6 +436,10 @@ static void free_tlbid_vdomain(struct kvm *kvm) kfree(vdomain); } +#else +static inline int kvm_arm_init_tlbidomain(struct kvm *kvm) { return 0; } +static inline void free_tlbid_vdomain(struct kvm *kvm) { } +#endif /** * kvm_arch_init_vm - initializes a VM data structure @@ -705,7 +710,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif case KVM_CAP_ARM_TLBIDOMAIN: - if (system_supports_tlbid()) + if (IS_ENABLED(CONFIG_KVM_ARM_VTLBID) && system_supports_tlbid()) r = 1; else r = 0; @@ -872,6 +877,7 @@ static void update_steal_time(struct kvm_vcpu *vcpu) } #endif +#ifdef CONFIG_KVM_ARM_VTLBID static bool is_vcpu_in_vdomain(u32 vdomain_bitmap, int vdomain_idx) { return vdomain_bitmap & BIT(vdomain_idx); @@ -1130,6 +1136,11 @@ static void kvm_tlbidomain_vcpu_put(struct kvm_vcpu *vcpu) for (i = 0; i < VTLBID_EL2_MAX_REGS; i++) vtlbidn_clear_set_s(i, VTLBID0_EL2_TD, 0); } +#else +static inline void kvm_vcpu_reload_tlbid(struct kvm *kvm) { } +static inline void kvm_tlbidomain_vcpu_load(struct kvm_vcpu *vcpu) { } +static inline void kvm_tlbidomain_vcpu_put(struct kvm_vcpu *vcpu) { } +#endif void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { @@ -2157,6 +2168,7 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, return kvm_reset_vcpu(vcpu); } +#ifdef CONFIG_KVM_ARM_VTLBID static int kvm_arm_tlbidomain_vcpu_init(struct kvm_vcpu *vcpu) { struct tlbidomain *vdomain; @@ -2198,6 +2210,9 @@ static int kvm_arm_tlbidomain_vcpu_init(struct kvm_vcpu *vcpu) return 0; } +#else +static inline int kvm_arm_tlbidomain_vcpu_init(struct kvm_vcpu *vcpu) { return 0; } +#endif static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) @@ -2348,6 +2363,7 @@ static int kvm_arm_vcpu_rmm_psci_complete(struct kvm_vcpu *vcpu, return realm_psci_complete(vcpu, target, arg->psci_status); } +#ifdef CONFIG_KVM_ARM_VTLBID static int kvm_arm_vcpu_set_vdomain(struct kvm_vcpu *vcpu, struct kvm_arm_set_vdomain *vdomain) { @@ -2385,6 +2401,13 @@ static int kvm_arm_vcpu_set_vdomain(struct kvm_vcpu *vcpu, return 0; } +#else +static inline int kvm_arm_vcpu_set_vdomain(struct kvm_vcpu *vcpu, + struct kvm_arm_set_vdomain *vdomain) +{ + return -EINVAL; +} +#endif long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) @@ -2595,6 +2618,7 @@ static int kvm_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) } } +#ifdef CONFIG_KVM_ARM_VTLBID static int kvm_arm_get_vdomain_num(struct kvm *kvm, struct kvm_arm_get_vdomain *vdomain) { @@ -2607,6 +2631,13 @@ static int kvm_arm_get_vdomain_num(struct kvm *kvm, return 0; } +#else +static inline int kvm_arm_get_vdomain_num(struct kvm *kvm, + struct kvm_arm_get_vdomain *vdomain) +{ + return -EINVAL; +} +#endif int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index ec36a6a3262d..5d2121ac8a88 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -276,6 +276,7 @@ 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) @@ -288,6 +289,14 @@ static bool access_tlbididr(struct kvm_vcpu *vcpu, 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, @@ -3795,6 +3804,7 @@ const struct sys_reg_desc *get_reg_by_id(u64 id, /* * 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_tlbidomain(kvm); @@ -3825,6 +3835,7 @@ void kvm_update_aa64mmfr4_tlbid(struct kvm *kvm) mutex_unlock(&kvm->arch.config_lock); } +#endif /* Decode an index value, and find the sys_reg_desc entry. */ static const struct sys_reg_desc * diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 4c5ae75bc9eb..8a2415921ba0 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -238,7 +238,11 @@ 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 -- 2.33.0