Register the TLBID field of ID_AA64MMFR4_EL1 in the sysreg properties table so the writable-idreg machinery exposes it as a property when KVM reports the bits writable. Add kvm_arm_vtlbid_init(), called from kvm_arch_init_vcpu(). When running on the virt machine with TLBI vdomains configured, it computes the vCPU's domain bitmap via virt_cpu_vdomain_bitmap() and sends the KVM_ARM_VCPU_SET_VDOMAIN ioctl, whose uapi is added to linux-headers. It is a no-op when no vdomains are configured (vms->num_vdomains == 0) or on non-virt machines. The ioctl is only sent before the VM starts running (!runstate_is_running()). All possible vCPUs, including currently unplugged ones, have their vdomain configured at startup, so there is no need to re-send it during vCPU hot-plug; the kernel rejects re-writing the ID register after the VM has run once, which otherwise hangs the VM. Finally, read ID_AA64MMFR4_EL1 back from KVM into isar so the TLBID bit survives vCPU hot-plug: a hot-plugged ARMCPU is recreated with MMFR4 reset to 0 (stage-0 feature detection does not read MMFR4), and kvm_arm_writable_idregs_to_cpreg_list() would otherwise overwrite the KVM-configured value with 0. Signed-off-by: Tian Zheng <zhengtian10@huawei.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- linux-headers/linux/kvm.h | 7 ++++ target/arm/cpu-sysreg-properties.c | 1 + target/arm/kvm64.c | 58 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4d5792a95d..968c202188 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1849,4 +1849,11 @@ struct kvm_arm_get_vdomain { #define KVM_ARM_GET_VDOMAIN_NUM _IOW(KVMIO, 0xd7, struct kvm_arm_get_vdomain) +struct kvm_arm_set_vdomain { + __u32 vdomain_bitmap; + __u8 num_vdomains; +}; + +#define KVM_ARM_VCPU_SET_VDOMAIN _IOW(KVMIO, 0xd8, struct kvm_arm_set_vdomain) + #endif /* __LINUX_KVM_H */ diff --git a/target/arm/cpu-sysreg-properties.c b/target/arm/cpu-sysreg-properties.c index c8a43c9eb4..41bd5b13cb 100644 --- a/target/arm/cpu-sysreg-properties.c +++ b/target/arm/cpu-sysreg-properties.c @@ -561,6 +561,7 @@ void initialize_cpu_sysreg_properties(void) ARM64SysReg *ID_AA64MMFR4_EL1 = arm64_sysreg_get(ID_AA64MMFR4_EL1_IDX); ID_AA64MMFR4_EL1->name = "ID_AA64MMFR4_EL1"; arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "SRMASK", 44, 47); + arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "TLBID", 40, 43); arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "E3DSE", 36, 39); arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "RMEGDI", 28, 31); arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "E2H0", 24, 27); diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index a1255956f3..fd43dfe1d6 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -33,6 +33,7 @@ #include "cpu-features.h" #include "hw/acpi/acpi.h" #include "hw/acpi/ghes.h" +#include "hw/arm/virt.h" #include "cpu-custom.h" static bool have_guest_debug; @@ -898,6 +899,57 @@ static int kvm_arm_set_pv_unhalt_bmap(ARMCPU *cpu) return kvm_set_one_reg(CPU(cpu), KVM_REG_ARM_VENDOR_HYP_BMAP, &bmap); } +static int kvm_arm_vtlbid_init(CPUState *cs) +{ + VirtMachineState *vms; + ARMCPU *cpu = ARM_CPU(cs); + uint32_t vdomain_bitmap; + struct kvm_arm_set_vdomain config; + int ret = 0; + + if (!kvm_arm_vtlbid_supported()) { + return ret; + } + + vms = VIRT_MACHINE(object_dynamic_cast(OBJECT(qdev_get_machine()), + TYPE_VIRT_MACHINE)); + if (!vms || vms->num_vdomains == 0) { + return ret; + } + + vdomain_bitmap = virt_cpu_vdomain_bitmap(vms, cs->cpu_index); + if (vdomain_bitmap == 0) { + return ret; + } + + if (!runstate_is_running()) { + config = (struct kvm_arm_set_vdomain){ + .vdomain_bitmap = vdomain_bitmap, + .num_vdomains = vms->num_vdomains, + }; + ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_SET_VDOMAIN, &config); + if (ret < 0) { + error_report("vCPU %d: Failed to set vdomain bitmap (0x%x) " + "with %d vdomains: %s", + cs->cpu_index, vdomain_bitmap, vms->num_vdomains, + strerror(-ret)); + return ret; + } + qemu_log("vCPU %d: Set vdomain_bitmap=0x%x num_vdomains=%d\n", + cs->cpu_index, vdomain_bitmap, vms->num_vdomains); + } + + ret = kvm_get_one_reg(cs, + idregs_sysreg_to_kvm_reg( + id_register_sysreg[ID_AA64MMFR4_EL1_IDX]), + &cpu->isar.idregs[ID_AA64MMFR4_EL1_IDX]); + if (ret) + error_report("vCPU %d: Failed to read ID_AA64MMFR4_EL1: %s", + cs->cpu_index, strerror(-ret)); + + return ret; +} + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 #define ARM_CPU_ID_CLIDR 3, 1, 0, 0, 1 @@ -982,6 +1034,12 @@ int kvm_arch_init_vcpu(CPUState *cs) /* Don't abort, as pvspinlock is optional */ } } + + ret = kvm_arm_vtlbid_init(cs); + if (ret) { + return ret; + } + /* * KVM reports the exact PSCI version it is implementing via a * special sysreg. If it is present, use its contents to determine -- 2.33.0