forked from Minki/linux
KVM: PPC: Book3S HV: Add a debugfs file to dump radix mappings
This adds a file called 'radix' in the debugfs directory for the guest, which when read gives all of the valid leaf PTEs in the partition-scoped radix tree for a radix guest, in human-readable format. It is analogous to the existing 'htab' file which dumps the HPT entries for a HPT guest. Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
32eb150aee
commit
9a94d3ee2d
@ -435,6 +435,7 @@ static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm)
|
||||
}
|
||||
|
||||
extern void kvmppc_mmu_debugfs_init(struct kvm *kvm);
|
||||
extern void kvmhv_radix_debugfs_init(struct kvm *kvm);
|
||||
|
||||
extern void kvmhv_rm_send_ipi(int cpu);
|
||||
|
||||
|
@ -291,6 +291,7 @@ struct kvm_arch {
|
||||
u64 process_table;
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *htab_dentry;
|
||||
struct dentry *radix_dentry;
|
||||
struct kvm_resize_hpt *resize_hpt; /* protected by kvm->lock */
|
||||
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
|
||||
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/kvm.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <asm/kvm_ppc.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
@ -853,6 +856,182 @@ static void pmd_ctor(void *addr)
|
||||
memset(addr, 0, RADIX_PMD_TABLE_SIZE);
|
||||
}
|
||||
|
||||
struct debugfs_radix_state {
|
||||
struct kvm *kvm;
|
||||
struct mutex mutex;
|
||||
unsigned long gpa;
|
||||
int chars_left;
|
||||
int buf_index;
|
||||
char buf[128];
|
||||
u8 hdr;
|
||||
};
|
||||
|
||||
static int debugfs_radix_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kvm *kvm = inode->i_private;
|
||||
struct debugfs_radix_state *p;
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
kvm_get_kvm(kvm);
|
||||
p->kvm = kvm;
|
||||
mutex_init(&p->mutex);
|
||||
file->private_data = p;
|
||||
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
||||
static int debugfs_radix_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct debugfs_radix_state *p = file->private_data;
|
||||
|
||||
kvm_put_kvm(p->kvm);
|
||||
kfree(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t debugfs_radix_read(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct debugfs_radix_state *p = file->private_data;
|
||||
ssize_t ret, r;
|
||||
unsigned long n;
|
||||
struct kvm *kvm;
|
||||
unsigned long gpa;
|
||||
pgd_t *pgt;
|
||||
pgd_t pgd, *pgdp;
|
||||
pud_t pud, *pudp;
|
||||
pmd_t pmd, *pmdp;
|
||||
pte_t *ptep;
|
||||
int shift;
|
||||
unsigned long pte;
|
||||
|
||||
kvm = p->kvm;
|
||||
if (!kvm_is_radix(kvm))
|
||||
return 0;
|
||||
|
||||
ret = mutex_lock_interruptible(&p->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (p->chars_left) {
|
||||
n = p->chars_left;
|
||||
if (n > len)
|
||||
n = len;
|
||||
r = copy_to_user(buf, p->buf + p->buf_index, n);
|
||||
n -= r;
|
||||
p->chars_left -= n;
|
||||
p->buf_index += n;
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret = n;
|
||||
if (r) {
|
||||
if (!n)
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
gpa = p->gpa;
|
||||
pgt = kvm->arch.pgtable;
|
||||
while (len != 0 && gpa < RADIX_PGTABLE_RANGE) {
|
||||
if (!p->hdr) {
|
||||
n = scnprintf(p->buf, sizeof(p->buf),
|
||||
"pgdir: %lx\n", (unsigned long)pgt);
|
||||
p->hdr = 1;
|
||||
goto copy;
|
||||
}
|
||||
|
||||
pgdp = pgt + pgd_index(gpa);
|
||||
pgd = READ_ONCE(*pgdp);
|
||||
if (!(pgd_val(pgd) & _PAGE_PRESENT)) {
|
||||
gpa = (gpa & PGDIR_MASK) + PGDIR_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
pudp = pud_offset(&pgd, gpa);
|
||||
pud = READ_ONCE(*pudp);
|
||||
if (!(pud_val(pud) & _PAGE_PRESENT)) {
|
||||
gpa = (gpa & PUD_MASK) + PUD_SIZE;
|
||||
continue;
|
||||
}
|
||||
if (pud_val(pud) & _PAGE_PTE) {
|
||||
pte = pud_val(pud);
|
||||
shift = PUD_SHIFT;
|
||||
goto leaf;
|
||||
}
|
||||
|
||||
pmdp = pmd_offset(&pud, gpa);
|
||||
pmd = READ_ONCE(*pmdp);
|
||||
if (!(pmd_val(pmd) & _PAGE_PRESENT)) {
|
||||
gpa = (gpa & PMD_MASK) + PMD_SIZE;
|
||||
continue;
|
||||
}
|
||||
if (pmd_val(pmd) & _PAGE_PTE) {
|
||||
pte = pmd_val(pmd);
|
||||
shift = PMD_SHIFT;
|
||||
goto leaf;
|
||||
}
|
||||
|
||||
ptep = pte_offset_kernel(&pmd, gpa);
|
||||
pte = pte_val(READ_ONCE(*ptep));
|
||||
if (!(pte & _PAGE_PRESENT)) {
|
||||
gpa += PAGE_SIZE;
|
||||
continue;
|
||||
}
|
||||
shift = PAGE_SHIFT;
|
||||
leaf:
|
||||
n = scnprintf(p->buf, sizeof(p->buf),
|
||||
" %lx: %lx %d\n", gpa, pte, shift);
|
||||
gpa += 1ul << shift;
|
||||
copy:
|
||||
p->chars_left = n;
|
||||
if (n > len)
|
||||
n = len;
|
||||
r = copy_to_user(buf, p->buf, n);
|
||||
n -= r;
|
||||
p->chars_left -= n;
|
||||
p->buf_index = n;
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret += n;
|
||||
if (r) {
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->gpa = gpa;
|
||||
|
||||
out:
|
||||
mutex_unlock(&p->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t debugfs_radix_write(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static const struct file_operations debugfs_radix_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = debugfs_radix_open,
|
||||
.release = debugfs_radix_release,
|
||||
.read = debugfs_radix_read,
|
||||
.write = debugfs_radix_write,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
void kvmhv_radix_debugfs_init(struct kvm *kvm)
|
||||
{
|
||||
kvm->arch.radix_dentry = debugfs_create_file("radix", 0400,
|
||||
kvm->arch.debugfs_dir, kvm,
|
||||
&debugfs_radix_fops);
|
||||
}
|
||||
|
||||
int kvmppc_radix_init(void)
|
||||
{
|
||||
unsigned long size = sizeof(void *) << RADIX_PTE_INDEX_SIZE;
|
||||
|
@ -4485,6 +4485,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
|
||||
snprintf(buf, sizeof(buf), "vm%d", current->pid);
|
||||
kvm->arch.debugfs_dir = debugfs_create_dir(buf, kvm_debugfs_dir);
|
||||
kvmppc_mmu_debugfs_init(kvm);
|
||||
if (radix_enabled())
|
||||
kvmhv_radix_debugfs_init(kvm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user