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


Reply via email to