in kvm/book3s_64_mmu_radix.c [1288:1438]
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;
struct kvm_nested_guest *nested;
pgd_t *pgdp;
p4d_t p4d, *p4dp;
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;
nested = NULL;
pgt = NULL;
while (len != 0 && p->lpid >= 0) {
if (gpa >= RADIX_PGTABLE_RANGE) {
gpa = 0;
pgt = NULL;
if (nested) {
kvmhv_put_nested(nested);
nested = NULL;
}
p->lpid = kvmhv_nested_next_lpid(kvm, p->lpid);
p->hdr = 0;
if (p->lpid < 0)
break;
}
if (!pgt) {
if (p->lpid == 0) {
pgt = kvm->arch.pgtable;
} else {
nested = kvmhv_get_nested(kvm, p->lpid, false);
if (!nested) {
gpa = RADIX_PGTABLE_RANGE;
continue;
}
pgt = nested->shadow_pgtable;
}
}
n = 0;
if (!p->hdr) {
if (p->lpid > 0)
n = scnprintf(p->buf, sizeof(p->buf),
"\nNested LPID %d: ", p->lpid);
n += scnprintf(p->buf + n, sizeof(p->buf) - n,
"pgdir: %lx\n", (unsigned long)pgt);
p->hdr = 1;
goto copy;
}
pgdp = pgt + pgd_index(gpa);
p4dp = p4d_offset(pgdp, gpa);
p4d = READ_ONCE(*p4dp);
if (!(p4d_val(p4d) & _PAGE_PRESENT)) {
gpa = (gpa & P4D_MASK) + P4D_SIZE;
continue;
}
pudp = pud_offset(&p4d, 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;
if (nested)
kvmhv_put_nested(nested);
out:
mutex_unlock(&p->mutex);
return ret;
}