xref: /openbmc/linux/arch/x86/kvm/debugfs.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
120c8ccb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2235539b4SLuiz Capitulino /*
3235539b4SLuiz Capitulino  * Kernel-based Virtual Machine driver for Linux
4235539b4SLuiz Capitulino  *
5235539b4SLuiz Capitulino  * Copyright 2016 Red Hat, Inc. and/or its affiliates.
6235539b4SLuiz Capitulino  */
7*8d20bd63SSean Christopherson #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8*8d20bd63SSean Christopherson 
9235539b4SLuiz Capitulino #include <linux/kvm_host.h>
104f5758fcSLuiz Capitulino #include <linux/debugfs.h>
1116ba3ab4SWanpeng Li #include "lapic.h"
123bcd0662SPeter Xu #include "mmu.h"
133bcd0662SPeter Xu #include "mmu/mmu_internal.h"
14235539b4SLuiz Capitulino 
vcpu_get_timer_advance_ns(void * data,u64 * val)1516ba3ab4SWanpeng Li static int vcpu_get_timer_advance_ns(void *data, u64 *val)
1616ba3ab4SWanpeng Li {
1716ba3ab4SWanpeng Li 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
1816ba3ab4SWanpeng Li 	*val = vcpu->arch.apic->lapic_timer.timer_advance_ns;
1916ba3ab4SWanpeng Li 	return 0;
2016ba3ab4SWanpeng Li }
2116ba3ab4SWanpeng Li 
2216ba3ab4SWanpeng Li DEFINE_SIMPLE_ATTRIBUTE(vcpu_timer_advance_ns_fops, vcpu_get_timer_advance_ns, NULL, "%llu\n");
2316ba3ab4SWanpeng Li 
vcpu_get_guest_mode(void * data,u64 * val)24d5a0483fSKrish Sadhukhan static int vcpu_get_guest_mode(void *data, u64 *val)
25d5a0483fSKrish Sadhukhan {
26d5a0483fSKrish Sadhukhan 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
27d5a0483fSKrish Sadhukhan 	*val = vcpu->stat.guest_mode;
28d5a0483fSKrish Sadhukhan 	return 0;
29d5a0483fSKrish Sadhukhan }
30d5a0483fSKrish Sadhukhan 
31d5a0483fSKrish Sadhukhan DEFINE_SIMPLE_ATTRIBUTE(vcpu_guest_mode_fops, vcpu_get_guest_mode, NULL, "%lld\n");
32d5a0483fSKrish Sadhukhan 
vcpu_get_tsc_offset(void * data,u64 * val)334f5758fcSLuiz Capitulino static int vcpu_get_tsc_offset(void *data, u64 *val)
344f5758fcSLuiz Capitulino {
354f5758fcSLuiz Capitulino 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
364f5758fcSLuiz Capitulino 	*val = vcpu->arch.tsc_offset;
374f5758fcSLuiz Capitulino 	return 0;
384f5758fcSLuiz Capitulino }
394f5758fcSLuiz Capitulino 
404f5758fcSLuiz Capitulino DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_offset_fops, vcpu_get_tsc_offset, NULL, "%lld\n");
414f5758fcSLuiz Capitulino 
vcpu_get_tsc_scaling_ratio(void * data,u64 * val)424f5758fcSLuiz Capitulino static int vcpu_get_tsc_scaling_ratio(void *data, u64 *val)
434f5758fcSLuiz Capitulino {
444f5758fcSLuiz Capitulino 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
454f5758fcSLuiz Capitulino 	*val = vcpu->arch.tsc_scaling_ratio;
464f5758fcSLuiz Capitulino 	return 0;
474f5758fcSLuiz Capitulino }
484f5758fcSLuiz Capitulino 
494f5758fcSLuiz Capitulino DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_fops, vcpu_get_tsc_scaling_ratio, NULL, "%llu\n");
504f5758fcSLuiz Capitulino 
vcpu_get_tsc_scaling_frac_bits(void * data,u64 * val)514f5758fcSLuiz Capitulino static int vcpu_get_tsc_scaling_frac_bits(void *data, u64 *val)
524f5758fcSLuiz Capitulino {
53938c8745SSean Christopherson 	*val = kvm_caps.tsc_scaling_ratio_frac_bits;
544f5758fcSLuiz Capitulino 	return 0;
554f5758fcSLuiz Capitulino }
564f5758fcSLuiz Capitulino 
574f5758fcSLuiz Capitulino DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_frac_fops, vcpu_get_tsc_scaling_frac_bits, NULL, "%llu\n");
584f5758fcSLuiz Capitulino 
kvm_arch_create_vcpu_debugfs(struct kvm_vcpu * vcpu,struct dentry * debugfs_dentry)59d56f5136SPaolo Bonzini void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry)
60235539b4SLuiz Capitulino {
61d5a0483fSKrish Sadhukhan 	debugfs_create_file("guest_mode", 0444, debugfs_dentry, vcpu,
62d5a0483fSKrish Sadhukhan 			    &vcpu_guest_mode_fops);
63d56f5136SPaolo Bonzini 	debugfs_create_file("tsc-offset", 0444, debugfs_dentry, vcpu,
643e7093d0SGreg KH 			    &vcpu_tsc_offset_fops);
654f5758fcSLuiz Capitulino 
663e7093d0SGreg KH 	if (lapic_in_kernel(vcpu))
673e7093d0SGreg KH 		debugfs_create_file("lapic_timer_advance_ns", 0444,
68d56f5136SPaolo Bonzini 				    debugfs_dentry, vcpu,
693e7093d0SGreg KH 				    &vcpu_timer_advance_ns_fops);
7016ba3ab4SWanpeng Li 
71938c8745SSean Christopherson 	if (kvm_caps.has_tsc_control) {
723e7093d0SGreg KH 		debugfs_create_file("tsc-scaling-ratio", 0444,
73d56f5136SPaolo Bonzini 				    debugfs_dentry, vcpu,
743e7093d0SGreg KH 				    &vcpu_tsc_scaling_fops);
753e7093d0SGreg KH 		debugfs_create_file("tsc-scaling-ratio-frac-bits", 0444,
76d56f5136SPaolo Bonzini 				    debugfs_dentry, vcpu,
773e7093d0SGreg KH 				    &vcpu_tsc_scaling_frac_fops);
784f5758fcSLuiz Capitulino 	}
79235539b4SLuiz Capitulino }
803bcd0662SPeter Xu 
813bcd0662SPeter Xu /*
823bcd0662SPeter Xu  * This covers statistics <1024 (11=log(1024)+1), which should be enough to
833bcd0662SPeter Xu  * cover RMAP_RECYCLE_THRESHOLD.
843bcd0662SPeter Xu  */
853bcd0662SPeter Xu #define  RMAP_LOG_SIZE  11
863bcd0662SPeter Xu 
873bcd0662SPeter Xu static const char *kvm_lpage_str[KVM_NR_PAGE_SIZES] = { "4K", "2M", "1G" };
883bcd0662SPeter Xu 
kvm_mmu_rmaps_stat_show(struct seq_file * m,void * v)893bcd0662SPeter Xu static int kvm_mmu_rmaps_stat_show(struct seq_file *m, void *v)
903bcd0662SPeter Xu {
913bcd0662SPeter Xu 	struct kvm_rmap_head *rmap;
923bcd0662SPeter Xu 	struct kvm *kvm = m->private;
933bcd0662SPeter Xu 	struct kvm_memory_slot *slot;
943bcd0662SPeter Xu 	struct kvm_memslots *slots;
953bcd0662SPeter Xu 	unsigned int lpage_size, index;
963bcd0662SPeter Xu 	/* Still small enough to be on the stack */
973bcd0662SPeter Xu 	unsigned int *log[KVM_NR_PAGE_SIZES], *cur;
983bcd0662SPeter Xu 	int i, j, k, l, ret;
993bcd0662SPeter Xu 
100fffb5323SNikunj A Dadhania 	if (!kvm_memslots_have_rmaps(kvm))
101fffb5323SNikunj A Dadhania 		return 0;
102fffb5323SNikunj A Dadhania 
1033bcd0662SPeter Xu 	ret = -ENOMEM;
1043bcd0662SPeter Xu 	memset(log, 0, sizeof(log));
1053bcd0662SPeter Xu 	for (i = 0; i < KVM_NR_PAGE_SIZES; i++) {
1063bcd0662SPeter Xu 		log[i] = kcalloc(RMAP_LOG_SIZE, sizeof(unsigned int), GFP_KERNEL);
1073bcd0662SPeter Xu 		if (!log[i])
1083bcd0662SPeter Xu 			goto out;
1093bcd0662SPeter Xu 	}
1103bcd0662SPeter Xu 
1113bcd0662SPeter Xu 	mutex_lock(&kvm->slots_lock);
1123bcd0662SPeter Xu 	write_lock(&kvm->mmu_lock);
1133bcd0662SPeter Xu 
1143bcd0662SPeter Xu 	for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
115a54d8066SMaciej S. Szmigiero 		int bkt;
116a54d8066SMaciej S. Szmigiero 
1173bcd0662SPeter Xu 		slots = __kvm_memslots(kvm, i);
118a54d8066SMaciej S. Szmigiero 		kvm_for_each_memslot(slot, bkt, slots)
1193bcd0662SPeter Xu 			for (k = 0; k < KVM_NR_PAGE_SIZES; k++) {
1203bcd0662SPeter Xu 				rmap = slot->arch.rmap[k];
1213bcd0662SPeter Xu 				lpage_size = kvm_mmu_slot_lpages(slot, k + 1);
1223bcd0662SPeter Xu 				cur = log[k];
1233bcd0662SPeter Xu 				for (l = 0; l < lpage_size; l++) {
1243bcd0662SPeter Xu 					index = ffs(pte_list_count(&rmap[l]));
1253bcd0662SPeter Xu 					if (WARN_ON_ONCE(index >= RMAP_LOG_SIZE))
1263bcd0662SPeter Xu 						index = RMAP_LOG_SIZE - 1;
1273bcd0662SPeter Xu 					cur[index]++;
1283bcd0662SPeter Xu 				}
1293bcd0662SPeter Xu 			}
1303bcd0662SPeter Xu 	}
1313bcd0662SPeter Xu 
1323bcd0662SPeter Xu 	write_unlock(&kvm->mmu_lock);
1333bcd0662SPeter Xu 	mutex_unlock(&kvm->slots_lock);
1343bcd0662SPeter Xu 
1353bcd0662SPeter Xu 	/* index=0 counts no rmap; index=1 counts 1 rmap */
1363bcd0662SPeter Xu 	seq_printf(m, "Rmap_Count:\t0\t1\t");
1373bcd0662SPeter Xu 	for (i = 2; i < RMAP_LOG_SIZE; i++) {
1383bcd0662SPeter Xu 		j = 1 << (i - 1);
1393bcd0662SPeter Xu 		k = (1 << i) - 1;
1403bcd0662SPeter Xu 		seq_printf(m, "%d-%d\t", j, k);
1413bcd0662SPeter Xu 	}
1423bcd0662SPeter Xu 	seq_printf(m, "\n");
1433bcd0662SPeter Xu 
1443bcd0662SPeter Xu 	for (i = 0; i < KVM_NR_PAGE_SIZES; i++) {
1453bcd0662SPeter Xu 		seq_printf(m, "Level=%s:\t", kvm_lpage_str[i]);
1463bcd0662SPeter Xu 		cur = log[i];
1473bcd0662SPeter Xu 		for (j = 0; j < RMAP_LOG_SIZE; j++)
1483bcd0662SPeter Xu 			seq_printf(m, "%d\t", cur[j]);
1493bcd0662SPeter Xu 		seq_printf(m, "\n");
1503bcd0662SPeter Xu 	}
1513bcd0662SPeter Xu 
1523bcd0662SPeter Xu 	ret = 0;
1533bcd0662SPeter Xu out:
1543bcd0662SPeter Xu 	for (i = 0; i < KVM_NR_PAGE_SIZES; i++)
1553bcd0662SPeter Xu 		kfree(log[i]);
1563bcd0662SPeter Xu 
1573bcd0662SPeter Xu 	return ret;
1583bcd0662SPeter Xu }
1593bcd0662SPeter Xu 
kvm_mmu_rmaps_stat_open(struct inode * inode,struct file * file)1603bcd0662SPeter Xu static int kvm_mmu_rmaps_stat_open(struct inode *inode, struct file *file)
1613bcd0662SPeter Xu {
1623bcd0662SPeter Xu 	struct kvm *kvm = inode->i_private;
1635aa02366SHou Wenlong 	int r;
1643bcd0662SPeter Xu 
1653bcd0662SPeter Xu 	if (!kvm_get_kvm_safe(kvm))
1663bcd0662SPeter Xu 		return -ENOENT;
1673bcd0662SPeter Xu 
1685aa02366SHou Wenlong 	r = single_open(file, kvm_mmu_rmaps_stat_show, kvm);
1695aa02366SHou Wenlong 	if (r < 0)
1705aa02366SHou Wenlong 		kvm_put_kvm(kvm);
1715aa02366SHou Wenlong 
1725aa02366SHou Wenlong 	return r;
1733bcd0662SPeter Xu }
1743bcd0662SPeter Xu 
kvm_mmu_rmaps_stat_release(struct inode * inode,struct file * file)1753bcd0662SPeter Xu static int kvm_mmu_rmaps_stat_release(struct inode *inode, struct file *file)
1763bcd0662SPeter Xu {
1773bcd0662SPeter Xu 	struct kvm *kvm = inode->i_private;
1783bcd0662SPeter Xu 
1793bcd0662SPeter Xu 	kvm_put_kvm(kvm);
1803bcd0662SPeter Xu 
1813bcd0662SPeter Xu 	return single_release(inode, file);
1823bcd0662SPeter Xu }
1833bcd0662SPeter Xu 
1843bcd0662SPeter Xu static const struct file_operations mmu_rmaps_stat_fops = {
1853bcd0662SPeter Xu 	.open		= kvm_mmu_rmaps_stat_open,
1863bcd0662SPeter Xu 	.read		= seq_read,
1873bcd0662SPeter Xu 	.llseek		= seq_lseek,
1883bcd0662SPeter Xu 	.release	= kvm_mmu_rmaps_stat_release,
1893bcd0662SPeter Xu };
1903bcd0662SPeter Xu 
kvm_arch_create_vm_debugfs(struct kvm * kvm)1913bcd0662SPeter Xu int kvm_arch_create_vm_debugfs(struct kvm *kvm)
1923bcd0662SPeter Xu {
1933bcd0662SPeter Xu 	debugfs_create_file("mmu_rmaps_stat", 0644, kvm->debugfs_dentry, kvm,
1943bcd0662SPeter Xu 			    &mmu_rmaps_stat_fops);
1953bcd0662SPeter Xu 	return 0;
1963bcd0662SPeter Xu }
197