arm64: mm: dump: make page table dumping reusable

For debugging purposes, it would be nice if we could export page tables
other than the swapper_pg_dir to userspace. To enable this, this patch
refactors the arm64 page table dumping code such that multiple tables
may be registered with the framework, and exported under debugfs.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Mark Rutland 2016-05-31 14:49:01 +01:00 committed by Catalin Marinas
parent 0e455d8e80
commit 4674fdb9f1
2 changed files with 64 additions and 12 deletions

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2014 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ASM_PTDUMP_H
#define __ASM_PTDUMP_H
#ifdef CONFIG_ARM64_PTDUMP
#include <linux/mm_types.h>
struct addr_marker {
unsigned long start_address;
char *name;
};
struct ptdump_info {
struct mm_struct *mm;
const struct addr_marker *markers;
unsigned long base_addr;
unsigned long max_addr;
};
int ptdump_register(struct ptdump_info *info, const char *name);
#else
static inline int ptdump_register(struct ptdump_info *info, const char *name)
{
return 0;
}
#endif /* CONFIG_ARM64_PTDUMP */
#endif /* __ASM_PTDUMP_H */

View File

@ -27,11 +27,7 @@
#include <asm/memory.h>
#include <asm/pgtable.h>
#include <asm/pgtable-hwdef.h>
struct addr_marker {
unsigned long start_address;
const char *name;
};
#include <asm/ptdump.h>
static const struct addr_marker address_markers[] = {
#ifdef CONFIG_KASAN
@ -290,7 +286,8 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
}
}
static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long start)
static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
unsigned long start)
{
pgd_t *pgd = pgd_offset(mm, 0UL);
unsigned i;
@ -309,12 +306,13 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long st
static int ptdump_show(struct seq_file *m, void *v)
{
struct ptdump_info *info = m->private;
struct pg_state st = {
.seq = m,
.marker = address_markers,
.marker = info->markers,
};
walk_pgd(&st, &init_mm, VA_START);
walk_pgd(&st, info->mm, info->base_addr);
note_page(&st, 0, 0, 0);
return 0;
@ -322,7 +320,7 @@ static int ptdump_show(struct seq_file *m, void *v)
static int ptdump_open(struct inode *inode, struct file *file)
{
return single_open(file, ptdump_show, NULL);
return single_open(file, ptdump_show, inode->i_private);
}
static const struct file_operations ptdump_fops = {
@ -332,7 +330,7 @@ static const struct file_operations ptdump_fops = {
.release = single_release,
};
static int ptdump_init(void)
int ptdump_register(struct ptdump_info *info, const char *name)
{
struct dentry *pe;
unsigned i, j;
@ -342,8 +340,18 @@ static int ptdump_init(void)
for (j = 0; j < pg_level[i].num; j++)
pg_level[i].mask |= pg_level[i].bits[j].mask;
pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
&ptdump_fops);
pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
return pe ? 0 : -ENOMEM;
}
static struct ptdump_info kernel_ptdump_info = {
.mm = &init_mm,
.markers = address_markers,
.base_addr = VA_START,
};
static int ptdump_init(void)
{
return ptdump_register(&kernel_ptdump_info, "kernel_page_tables");
}
device_initcall(ptdump_init);