KVM: arm64: Register AArch64 system register entries with the sysreg xarray
authorMarc Zyngier <maz@kernel.org>
Wed, 14 Feb 2024 13:18:15 +0000 (13:18 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Mon, 19 Feb 2024 17:13:01 +0000 (17:13 +0000)
In order to reduce the number of lookups that we have to perform
when handling a sysreg, register each AArch64 sysreg descriptor
with the global xarray. The index of the descriptor is stored
as a 10 bit field in the data word.

Subsequent patches will retrieve and use the stored index.

Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240214131827.2856277-15-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/emulate-nested.c
arch/arm64/kvm/sys_regs.c

index 8cda003d6267ab72f4d66a25428cdbd43bb0ad85..914fd54179bbe9fe7942d61ddfb24aff57ede743 100644 (file)
@@ -1078,6 +1078,9 @@ int kvm_handle_cp10_id(struct kvm_vcpu *vcpu);
 void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
 
 int __init kvm_sys_reg_table_init(void);
+struct sys_reg_desc;
+int __init populate_sysreg_config(const struct sys_reg_desc *sr,
+                                 unsigned int idx);
 int __init populate_nv_trap_config(void);
 
 bool lock_all_vcpus(struct kvm *kvm);
index 42f5b4483c806b2548d4103496b41f8642d6f807..ddf760b4dda57fc75066093c669e51439497ce94 100644 (file)
@@ -427,12 +427,14 @@ static const complex_condition_check ccc[] = {
  * [19:14]     bit number in the FGT register (6 bits)
  * [20]                trap polarity (1 bit)
  * [25:21]     FG filter (5 bits)
- * [62:26]     Unused (37 bits)
+ * [35:26]     Main SysReg table index (10 bits)
+ * [62:36]     Unused (27 bits)
  * [63]                RES0 - Must be zero, as lost on insertion in the xarray
  */
 #define TC_CGT_BITS    10
 #define TC_FGT_BITS    4
 #define TC_FGF_BITS    5
+#define TC_SRI_BITS    10
 
 union trap_config {
        u64     val;
@@ -442,7 +444,8 @@ union trap_config {
                unsigned long   bit:6;           /* Bit number */
                unsigned long   pol:1;           /* Polarity */
                unsigned long   fgf:TC_FGF_BITS; /* Fine Grained Filter */
-               unsigned long   unused:37;       /* Unused, should be zero */
+               unsigned long   sri:TC_SRI_BITS; /* SysReg Index */
+               unsigned long   unused:27;       /* Unused, should be zero */
                unsigned long   mbz:1;           /* Must Be Zero */
        };
 };
@@ -1868,6 +1871,38 @@ check_mcb:
        return ret;
 }
 
+int __init populate_sysreg_config(const struct sys_reg_desc *sr,
+                                 unsigned int idx)
+{
+       union trap_config tc;
+       u32 encoding;
+       void *ret;
+
+       /*
+        * 0 is a valid value for the index, but not for the storage.
+        * We'll store (idx+1), so check against an offset'd limit.
+        */
+       if (idx >= (BIT(TC_SRI_BITS) - 1)) {
+               kvm_err("sysreg %s (%d) out of range\n", sr->name, idx);
+               return -EINVAL;
+       }
+
+       encoding = sys_reg(sr->Op0, sr->Op1, sr->CRn, sr->CRm, sr->Op2);
+       tc = get_trap_config(encoding);
+
+       if (tc.sri) {
+               kvm_err("sysreg %s (%d) duplicate entry (%d)\n",
+                       sr->name, idx - 1, tc.sri);
+               return -EINVAL;
+       }
+
+       tc.sri = idx + 1;
+       ret = xa_store(&sr_forward_xa, encoding,
+                      xa_mk_value(tc.val), GFP_KERNEL);
+
+       return xa_err(ret);
+}
+
 static enum trap_behaviour get_behaviour(struct kvm_vcpu *vcpu,
                                         const struct trap_bits *tb)
 {
index 57f3d0c53fc3335acd3d79c573c5218eaa1415d5..a410e99f827eefdf287574835147b2dcb397b7b3 100644 (file)
@@ -3972,6 +3972,7 @@ int __init kvm_sys_reg_table_init(void)
        struct sys_reg_params params;
        bool valid = true;
        unsigned int i;
+       int ret = 0;
 
        /* Make sure tables are unique and in order. */
        valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);
@@ -3995,5 +3996,13 @@ int __init kvm_sys_reg_table_init(void)
        if (!first_idreg)
                return -EINVAL;
 
-       return populate_nv_trap_config();
+       ret = populate_nv_trap_config();
+
+       for (i = 0; !ret && i < ARRAY_SIZE(sys_reg_descs); i++)
+               ret = populate_sysreg_config(sys_reg_descs + i, i);
+
+       for (i = 0; !ret && i < ARRAY_SIZE(sys_insn_descs); i++)
+               ret = populate_sysreg_config(sys_insn_descs + i, i);
+
+       return ret;
 }