Commit 4674fdb9 authored by Mark Rutland's avatar Mark Rutland Committed by Catalin Marinas

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: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 0e455d8e
/*
* 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 */
...@@ -27,11 +27,7 @@ ...@@ -27,11 +27,7 @@
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgtable-hwdef.h> #include <asm/pgtable-hwdef.h>
#include <asm/ptdump.h>
struct addr_marker {
unsigned long start_address;
const char *name;
};
static const struct addr_marker address_markers[] = { static const struct addr_marker address_markers[] = {
#ifdef CONFIG_KASAN #ifdef CONFIG_KASAN
...@@ -290,7 +286,8 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) ...@@ -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); pgd_t *pgd = pgd_offset(mm, 0UL);
unsigned i; unsigned i;
...@@ -309,12 +306,13 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long st ...@@ -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) static int ptdump_show(struct seq_file *m, void *v)
{ {
struct ptdump_info *info = m->private;
struct pg_state st = { struct pg_state st = {
.seq = m, .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); note_page(&st, 0, 0, 0);
return 0; return 0;
...@@ -322,7 +320,7 @@ static int ptdump_show(struct seq_file *m, void *v) ...@@ -322,7 +320,7 @@ static int ptdump_show(struct seq_file *m, void *v)
static int ptdump_open(struct inode *inode, struct file *file) 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 = { static const struct file_operations ptdump_fops = {
...@@ -332,7 +330,7 @@ static const struct file_operations ptdump_fops = { ...@@ -332,7 +330,7 @@ static const struct file_operations ptdump_fops = {
.release = single_release, .release = single_release,
}; };
static int ptdump_init(void) int ptdump_register(struct ptdump_info *info, const char *name)
{ {
struct dentry *pe; struct dentry *pe;
unsigned i, j; unsigned i, j;
...@@ -342,8 +340,18 @@ static int ptdump_init(void) ...@@ -342,8 +340,18 @@ static int ptdump_init(void)
for (j = 0; j < pg_level[i].num; j++) for (j = 0; j < pg_level[i].num; j++)
pg_level[i].mask |= pg_level[i].bits[j].mask; pg_level[i].mask |= pg_level[i].bits[j].mask;
pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
&ptdump_fops);
return pe ? 0 : -ENOMEM; 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); device_initcall(ptdump_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment