The generic KVM_GET_ONE_REG loop cannot correctly read a handful of ID registers, so specially handle those:
- DCZID_EL0: No fine grain trap exists, hence not tracked by KVM. It is EL0-readable and untrapped, so read it directly with MRS. - CCSIDR_EL1/CCSIDR2_EL1: not plain ID registers, their value is selected by CSSELR_EL1. KVM only exposes them via the DEMUX API (KVM_REG_ARM_DEMUX_ID_CCSIDR), so there is no single value to read here. Skip them. - SMIDR_EL1: KVM does not support SME, so there is no meaningful host value. Skip it. - GMID_EL1: not in KVM's sys_reg_descs[] and, being an EL1 register, cannot be read from userspace via MRS either. The guest reads the raw host value; this is a genuine miss when MTE is enabled. Signed-off-by: Khushit Shah <[email protected]> --- target/arm/kvm.c | 53 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 42ff731f6e..6974e5c551 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -311,15 +311,50 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf) int ret; reg = &ahcf->isar.idregs[i]; - ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg)); - if (ret) { - if (errno == ENOENT) { - warn_report("%s error reading value of host %s register " - "(ENOENT)", __func__, sysregdesc->name); - } else { - error_report("%s error reading value of host %s register" - " (%m)", __func__, sysregdesc->name); - err = ret; + switch (i) { + case DCZID_EL0_IDX: + /* + * DCZID_EL0 is not in KVM's sys_reg_descs[], so + * KVM_GET_ONE_REG will fail. Read it directly from + * hardware since KVM doesn't trap guest reads of it. + */ + asm volatile("mrs %0, DCZID_EL0" : "=r" (*reg)); + break; + case CCSIDR_EL1_IDX: + case CCSIDR2_EL1_IDX: + /* + * CCSIDR_EL1 is not a plain ID register: the value it + * returns is selected by CSSELR_EL1, so there is no single + * value to capture here. It is exposed to userspace only via + * the DEMUX API (KVM_REG_ARM_DEMUX_ID_CCSIDR), indexed by + * CSSELR. Skip reading it here as there is no meaningful host + * value to read. + */ + break; + case SMIDR_EL1_IDX: + /* + * As SME is not yet supported by KVM, ignore reading SMIDR_EL1 + */ + break; + case GMID_EL1_IDX: + /* + * GMID_EL1 is not in KVM's sys_reg_descs[] and guest reads + * the raw host value. But as it is an EL1 register, we cannot + * read it directly. This is a genuine miss when MTE is + * enabled for the guest. + */ + break; + default: + ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg)); + if (ret) { + if (errno == ENOENT) { + warn_report("%s error reading value of host %s register " + "(ENOENT)", __func__, sysregdesc->name); + } else { + error_report("%s error reading value of host %s register" + " (%m)", __func__, sysregdesc->name); + err = ret; + } } } trace_get_host_cpu_idregs(sysregdesc->name, *reg); -- 2.52.0
