* This file is not tested, so may not compile/work
* correctly, out of the box.
#define pr_fmt(fmt) “page-walker: ” fmt
#include unsigned long pw_virt; void walk_address(struct mm_struct *mm, unsigned long virt) pgd = pgd_offset(mm, virt); p4d = p4d_offset(pgd, virt); pud = pud_offset(p4d, virt); pmd = pmd_offset(pud, virt); if (pmd_huge(*pmd)) { /* That’s a huge page */ pte = pte_offset_map(pmd, virt); pw_phys = PFN_PHYS((pte_pfn(*pte)); /*********************** sysfs ***********************/ static ssize_t address_show(struct kobject *kobj, static ssize_t address_store(struct kobject *kobj, mmap_read_lock(current->mm); return count; static struct attribute *page_walker_attrs[] = { static const struct attribute_group page_walker_attr_group = { static int __init page_walker_init(void) subsys_initcall(page_walker_init);
unsigned long pw_phys;
pw_phys = 0;
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (pgd_none(*pgd) || pgd_bad(*pgd) || !pgd_present(*pgd))
if (p4d_none(*p4d) || p4d_bad(*p4d) || !p4d_present(*p4d))
if (pud_none(*p4d) || pud_bad(*p4d) || !pud_present(*p4d))
if (pmd_none(*pmd) || pmd_bad(*pmd) || !pmd_present(*pmd))
pw_phys = pmd_address(*pmd);
if (pte_none(*pte) || !pte_present(*pte))
#define PAGE_WALKER_ATTR(_name) \
static struct kobj_attribute _name##_attr = __ATTR_RW(_name)
struct kobj_attribute *attr,
char *buf)
return sysfs_emit(buf, “%lu\n”, pw_phys);
struct kobj_attribute *attr,
const char *buf, size_t count)
err = kstrtoul(buf, 0, &pw_virt);
pr_err(“error during conversion\n”);
walk_address(current->mm, pw_virt);
mmap_read_unlock(current->mm);
PAGE_WALKER_ATTR(address);
&address_attr.attr,
.attrs = page_walker_attrs,
.name = “page_walker”,
#ifdef CONFIG_SYSFS
ret = sysfs_create_group(mm_kobj, &page_walker_attr_group);
if (ret) {
pr_err(“register sysfs failed\n”);
return ret;