Commit 89176658 authored by Marc Zyngier's avatar Marc Zyngier Committed by Oliver Upton
Browse files

KVM: arm64: Add debugfs file for guest's ID registers



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: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240214131827.2856277-27-maz@kernel.org


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent b80b701d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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;
+81 −0
Original line number Diff line number Diff line
@@ -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);
}