KVM: arm64: Add debugfs file for guest's ID registers
authorMarc Zyngier <maz@kernel.org>
Wed, 14 Feb 2024 13:18:27 +0000 (13:18 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Mon, 19 Feb 2024 17:13:02 +0000 (17:13 +0000)
Debugging ID register setup can be a complicated affair. Give the
kernel hacker a way to dump that state in an easy to parse way.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240214131827.2856277-27-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/sys_regs.c

index 3feabde9c926dac81ef16e88c0adb7e536beb4c0..181fef12e8e8708d2814959c7a36362aba79c739 100644 (file)
@@ -319,6 +319,9 @@ struct kvm_arch {
        /* PMCR_EL0.N value for the guest */
        u8 pmcr_n;
 
+       /* Iterator for idreg debugfs */
+       u8      idreg_debugfs_iter;
+
        /* Hypercall features firmware registers' descriptor */
        struct kvm_smccc_features smccc_feat;
        struct maple_tree smccc_filter;
index b5335e5a6e6ebec7107e69bcc62b18dd09ffcb98..e3faedc8b7a30d9d711e0355a5158fb2db257294 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/bitfield.h>
 #include <linux/bsearch.h>
 #include <linux/cacheinfo.h>
+#include <linux/debugfs.h>
 #include <linux/kvm_host.h>
 #include <linux/mm.h>
 #include <linux/printk.h>
@@ -3422,6 +3423,81 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu,
        return false;
 }
 
+static void *idregs_debug_start(struct seq_file *s, loff_t *pos)
+{
+       struct kvm *kvm = s->private;
+       u8 *iter;
+
+       mutex_lock(&kvm->arch.config_lock);
+
+       iter = &kvm->arch.idreg_debugfs_iter;
+       if (*iter == (u8)~0) {
+               *iter = *pos;
+               if (*iter >= KVM_ARM_ID_REG_NUM)
+                       iter = NULL;
+       } else {
+               iter = ERR_PTR(-EBUSY);
+       }
+
+       mutex_unlock(&kvm->arch.config_lock);
+
+       return iter;
+}
+
+static void *idregs_debug_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct kvm *kvm = s->private;
+
+       (*pos)++;
+
+       if ((kvm->arch.idreg_debugfs_iter + 1) < KVM_ARM_ID_REG_NUM) {
+               kvm->arch.idreg_debugfs_iter++;
+
+               return &kvm->arch.idreg_debugfs_iter;
+       }
+
+       return NULL;
+}
+
+static void idregs_debug_stop(struct seq_file *s, void *v)
+{
+       struct kvm *kvm = s->private;
+
+       if (IS_ERR(v))
+               return;
+
+       mutex_lock(&kvm->arch.config_lock);
+
+       kvm->arch.idreg_debugfs_iter = ~0;
+
+       mutex_unlock(&kvm->arch.config_lock);
+}
+
+static int idregs_debug_show(struct seq_file *s, void *v)
+{
+       struct kvm *kvm = s->private;
+       const struct sys_reg_desc *desc;
+
+       desc = first_idreg + kvm->arch.idreg_debugfs_iter;
+
+       if (!desc->name)
+               return 0;
+
+       seq_printf(s, "%20s:\t%016llx\n",
+                  desc->name, IDREG(kvm, IDX_IDREG(kvm->arch.idreg_debugfs_iter)));
+
+       return 0;
+}
+
+static const struct seq_operations idregs_debug_sops = {
+       .start  = idregs_debug_start,
+       .next   = idregs_debug_next,
+       .stop   = idregs_debug_stop,
+       .show   = idregs_debug_show,
+};
+
+DEFINE_SEQ_ATTRIBUTE(idregs_debug);
+
 static void kvm_reset_id_regs(struct kvm_vcpu *vcpu)
 {
        const struct sys_reg_desc *idreg = first_idreg;
@@ -3441,6 +3517,11 @@ static void kvm_reset_id_regs(struct kvm_vcpu *vcpu)
                id = reg_to_encoding(idreg);
        }
 
+       kvm->arch.idreg_debugfs_iter = ~0;
+
+       debugfs_create_file("idregs", 0444, kvm->debugfs_dentry, kvm,
+                           &idregs_debug_fops);
+
        set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
 }