Skip to contentSkip to conversation

arm64/ARM pt dumper changes

PATCH Superseded Ard Biesheuvel 4 participants 19 messages Apr 22, 2016 – May 31, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover arm64/ARM pt dumper changes

This series updates the kernel page table dumper to:
- not initialize the vmemmap region markers dynamically
- show region boundaries for the kasan shadow region
- include the UEFI runtime services mappings

Changes since v1:
- incorporated Mark Rutland's patches to split into separate sysfs files
- give ARM the same treatment so that we can export the UEFI page tables in code that is shared between ARM and arm64
- added file to use char arrays rather than char pointer in the marker and prot_bits arrays (arm64)

Ard Biesheuvel (4):
arm64: ptdump: use static initializers for vmemmap region boundaries
arm64: ptdump: add region marker for kasan shadow region
arm64: ptdump: fold string literals into address_markers[] and

    pte_bits[]

arm: mm: dump: make page table dumping reusable

Mark Rutland (2):
arm64: mm: dump: make page table dumping reusable efi/arm*: add support to dump the EFI page tables

 arch/arm/include/asm/ptdump.h      | 44 +++++++++
 arch/arm/mm/dump.c                 | 60 ++++++++-----
 arch/arm64/include/asm/ptdump.h    | 44 +++++++++
 arch/arm64/mm/dump.c               | 94 +++++++++-----------
 drivers/firmware/efi/arm-runtime.c | 21 +++++
 5 files changed, 188 insertions(+), 75 deletions(-)
 create mode 100644 arch/arm/include/asm/ptdump.h
 create mode 100644 arch/arm64/include/asm/ptdump.h
Signature · 1 line
2.7.4
#1 lore raw

PATCH v2 1/6 arm64: ptdump: use static initializers for vmemmap region boundaries

There is no need to initialize the vmemmap region boundaries dynamically, since they are compile time constants. So just add these constants to the global struct initializer, and drop the dynamic assignment and related code.

---
 arch/arm64/mm/dump.c | 49 ++++++--------------
 1 file changed, 13 insertions(+), 36 deletions(-)
arch/arm64/mm/dump.c +13 -36
index a21f47421b0c..493461159462 100644
@@ -32,37 +32,21 @@ struct addr_marker {
 	const char *name;
 };
 
-enum address_markers_idx {
-	MODULES_START_NR = 0,
-	MODULES_END_NR,
-	VMALLOC_START_NR,
-	VMALLOC_END_NR,
-	FIXADDR_START_NR,
-	FIXADDR_END_NR,
-	PCI_START_NR,
-	PCI_END_NR,
+static const struct addr_marker address_markers[] = {
+	{ MODULES_VADDR,		"Modules start" },
+	{ MODULES_END,			"Modules end" },
+	{ VMALLOC_START,		"vmalloc() Area" },
+	{ VMALLOC_END,			"vmalloc() End" },
+	{ FIXADDR_START,		"Fixmap start" },
+	{ FIXADDR_TOP,			"Fixmap end" },
+	{ PCI_IO_START,			"PCI I/O start" },
+	{ PCI_IO_END,			"PCI I/O end" },
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-	VMEMMAP_START_NR,
-	VMEMMAP_END_NR,
+	{ VMEMMAP_START,		"vmemmap start" },
+	{ VMEMMAP_START + VMEMMAP_SIZE,	"vmemmap end" },
 #endif
-	KERNEL_SPACE_NR,
-};
-
-static struct addr_marker address_markers[] = {
-	{ MODULES_VADDR,	"Modules start" },
-	{ MODULES_END,		"Modules end" },
-	{ VMALLOC_START,	"vmalloc() Area" },
-	{ VMALLOC_END,		"vmalloc() End" },
-	{ FIXADDR_START,	"Fixmap start" },
-	{ FIXADDR_TOP,		"Fixmap end" },
-	{ PCI_IO_START,		"PCI I/O start" },
-	{ PCI_IO_END,		"PCI I/O end" },
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-	{ 0,			"vmemmap start" },
-	{ 0,			"vmemmap end" },
-#endif
-	{ PAGE_OFFSET,		"Linear Mapping" },
-	{ -1,			NULL },
+	{ PAGE_OFFSET,			"Linear Mapping" },
+	{ -1,				NULL },
 };
 
 /*
@@ -347,13 +331,6 @@ static int ptdump_init(void)
 			for (j = 0; j < pg_level[i].num; j++)
 				pg_level[i].mask |= pg_level[i].bits[j].mask;
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-	address_markers[VMEMMAP_START_NR].start_address =
-				(unsigned long)virt_to_page(PAGE_OFFSET);
-	address_markers[VMEMMAP_END_NR].start_address =
-				(unsigned long)virt_to_page(high_memory);
-#endif
-
 	pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
 				 &ptdump_fops);
 	return pe ? 0 : -ENOMEM;
Signature · 1 line
2.7.4
reviewer
#2 lore raw

PATCH v2 1/6 arm64: ptdump: use static initializers for vmemmap region boundaries

Quoted 5 lines · Ard Biesheuvel

There is no need to initialize the vmemmap region boundaries dynamically, since they are compile time constants. So just add these constants to the global struct initializer, and drop the dynamic assignment and related code.

There is a slight change in that we now print the VA boundaries for the reserved vmemmap range rather than the populated vmemmap range, but that makes more sense to me anyway. It's nice to see the sepaarate indices go.

It may be worth defining VMEMMAP_END in the same header file as VMEMMAP_{START,SIZE}, but either way:

Mark.

Quoted 76 lines
---
 arch/arm64/mm/dump.c | 49 ++++++--------------
 1 file changed, 13 insertions(+), 36 deletions(-)
arch/arm64/mm/dump.c +13 -36
index a21f47421b0c..493461159462 100644
@@ -32,37 +32,21 @@ struct addr_marker {
 	const char *name;
 };
 
-enum address_markers_idx {
-	MODULES_START_NR = 0,
-	MODULES_END_NR,
-	VMALLOC_START_NR,
-	VMALLOC_END_NR,
-	FIXADDR_START_NR,
-	FIXADDR_END_NR,
-	PCI_START_NR,
-	PCI_END_NR,
+static const struct addr_marker address_markers[] = {
+	{ MODULES_VADDR,		"Modules start" },
+	{ MODULES_END,			"Modules end" },
+	{ VMALLOC_START,		"vmalloc() Area" },
+	{ VMALLOC_END,			"vmalloc() End" },
+	{ FIXADDR_START,		"Fixmap start" },
+	{ FIXADDR_TOP,			"Fixmap end" },
+	{ PCI_IO_START,			"PCI I/O start" },
+	{ PCI_IO_END,			"PCI I/O end" },
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-	VMEMMAP_START_NR,
-	VMEMMAP_END_NR,
+	{ VMEMMAP_START,		"vmemmap start" },
+	{ VMEMMAP_START + VMEMMAP_SIZE,	"vmemmap end" },
 #endif
-	KERNEL_SPACE_NR,
-};
-
-static struct addr_marker address_markers[] = {
-	{ MODULES_VADDR,	"Modules start" },
-	{ MODULES_END,		"Modules end" },
-	{ VMALLOC_START,	"vmalloc() Area" },
-	{ VMALLOC_END,		"vmalloc() End" },
-	{ FIXADDR_START,	"Fixmap start" },
-	{ FIXADDR_TOP,		"Fixmap end" },
-	{ PCI_IO_START,		"PCI I/O start" },
-	{ PCI_IO_END,		"PCI I/O end" },
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-	{ 0,			"vmemmap start" },
-	{ 0,			"vmemmap end" },
-#endif
-	{ PAGE_OFFSET,		"Linear Mapping" },
-	{ -1,			NULL },
+	{ PAGE_OFFSET,			"Linear Mapping" },
+	{ -1,				NULL },
 };
 
 /*
@@ -347,13 +331,6 @@ static int ptdump_init(void)
 			for (j = 0; j < pg_level[i].num; j++)
 				pg_level[i].mask |= pg_level[i].bits[j].mask;
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-	address_markers[VMEMMAP_START_NR].start_address =
-				(unsigned long)virt_to_page(PAGE_OFFSET);
-	address_markers[VMEMMAP_END_NR].start_address =
-				(unsigned long)virt_to_page(high_memory);
-#endif
-
 	pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
 				 &ptdump_fops);
 	return pe ? 0 : -ENOMEM;
Signature · 1 line
2.7.4
#3 lore raw

PATCH v2 2/6 arm64: ptdump: add region marker for kasan shadow region

In reply to Ard Biesheuvel

Annotate the KASAN shadow region with boundary markers, so that its mappings stand out in the page table dumper output.

---
 arch/arm64/mm/dump.c | 5 +++++
 1 file changed, 5 insertions(+)
arch/arm64/mm/dump.c +5 -0
index 493461159462..8404190fe2bd 100644
@@ -23,6 +23,7 @@
 #include <linux/seq_file.h>
 
 #include <asm/fixmap.h>
+#include <asm/kasan.h>
 #include <asm/memory.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
@@ -33,6 +34,10 @@ struct addr_marker {
 };
 
 static const struct addr_marker address_markers[] = {
+#ifdef CONFIG_KASAN
+	{ KASAN_SHADOW_START,		"Kasan shadow start" },
+	{ KASAN_SHADOW_END,		"Kasan shadow end" },
+#endif
 	{ MODULES_VADDR,		"Modules start" },
 	{ MODULES_END,			"Modules end" },
 	{ VMALLOC_START,		"vmalloc() Area" },
Signature · 1 line
2.7.4
reviewer
#4 lore raw

PATCH v2 2/6 arm64: ptdump: add region marker for kasan shadow region

Quoted 4 lines · Ard Biesheuvel

Annotate the KASAN shadow region with boundary markers, so that its mappings stand out in the page table dumper output.

Mark.

Quoted 30 lines
---
 arch/arm64/mm/dump.c | 5 +++++
 1 file changed, 5 insertions(+)
arch/arm64/mm/dump.c +5 -0
index 493461159462..8404190fe2bd 100644
@@ -23,6 +23,7 @@
 #include <linux/seq_file.h>
 
 #include <asm/fixmap.h>
+#include <asm/kasan.h>
 #include <asm/memory.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
@@ -33,6 +34,10 @@ struct addr_marker {
 };
 
 static const struct addr_marker address_markers[] = {
+#ifdef CONFIG_KASAN
+	{ KASAN_SHADOW_START,		"Kasan shadow start" },
+	{ KASAN_SHADOW_END,		"Kasan shadow end" },
+#endif
 	{ MODULES_VADDR,		"Modules start" },
 	{ MODULES_END,			"Modules end" },
 	{ VMALLOC_START,		"vmalloc() Area" },
Signature · 1 line
2.7.4
#5 lore raw

PATCH v2 3/6 arm64: ptdump: fold string literals into address_markers[] and pte_bits[]

In reply to Ard Biesheuvel

Replace the indirect string references in struct addr_marker and struct prot_bits with char array fields. Under a relocatable kernel, this not only saves 8 bytes in the absolute address that we no longer have to record, it also saves 24 bytes of init data (the size of a RELA entry) since this address no longer requires relocation processing at boot.

---
I am aware that this is a drop in the ocean, but I thought I'd include it anyway, since many people may not even realize that this issue exists in the first place.

---
 arch/arm64/mm/dump.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
arch/arm64/mm/dump.c +7 -7
index 8404190fe2bd..024f803e2fb4 100644
@@ -30,7 +30,7 @@
 
 struct addr_marker {
 	unsigned long start_address;
-	const char *name;
+	char name[32];
 };
 
 static const struct addr_marker address_markers[] = {
@@ -51,7 +51,7 @@ static const struct addr_marker address_markers[] = {
 	{ VMEMMAP_START + VMEMMAP_SIZE,	"vmemmap end" },
 #endif
 	{ PAGE_OFFSET,			"Linear Mapping" },
-	{ -1,				NULL },
+	{ -1 },
 };
 
 /*
@@ -69,10 +69,10 @@ struct pg_state {
 };
 
 struct prot_bits {
-	u64		mask;
-	u64		val;
-	const char	*set;
-	const char	*clear;
+	u64	mask;
+	u64	val;
+	char	set[16];
+	char	clear[8];
 };
 
 static const struct prot_bits pte_bits[] = {
@@ -184,7 +184,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
 		else
 			s = bits->clear;
 
-		if (s)
+		if (*s)
 			seq_printf(st->seq, " %s", s);
 	}
 }
Signature · 1 line
2.7.4
#6 lore raw

PATCH v2 4/6 arm64: mm: dump: make page table dumping reusable

In reply to Ard Biesheuvel

From: Mark Rutland <[email protected]>

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.

---
 arch/arm64/include/asm/ptdump.h | 44 ++++++++++++++++++++
 arch/arm64/mm/dump.c            | 32 ++++++++------
 2 files changed, 64 insertions(+), 12 deletions(-)
arch/arm64/include/asm/ptdump.h new file +44 -0
new file mode 100644
index 000000000000..fe82d693638a
@@ -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[32];
+};
+
+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 */
arch/arm64/mm/dump.c +20 -12
index 024f803e2fb4..73d7227d1403 100644
@@ -27,11 +27,7 @@
 #include <asm/memory.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
-
-struct addr_marker {
-	unsigned long start_address;
-	char name[32];
-};
+#include <asm/ptdump.h>
 
 static const struct addr_marker address_markers[] = {
 #ifdef CONFIG_KASAN
@@ -284,7 +280,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;
@@ -303,12 +300,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;
@@ -316,7 +314,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 = {
@@ -326,7 +324,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;
@@ -336,8 +334,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);
Signature · 1 line
2.7.4
#7 lore raw

PATCH v2 4/6 arm64: mm: dump: make page table dumping reusable

Hi Ard, Mark,

Quoted 7 lines · Ard Biesheuvel

From: Mark Rutland <[email protected]>

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.

Quoted 6 lines
---
 arch/arm64/include/asm/ptdump.h | 44 ++++++++++++++++++++
 arch/arm64/mm/dump.c            | 32 ++++++++------
 2 files changed, 64 insertions(+), 12 deletions(-)

Could you reorder this with patch 3, please? I'm unsure about the benefit of the very specific string literal changes, but the ptdump stuff here certainly looks beneficial.

I can queue the first two patches as-is.

Thanks.

Will

reviewer
#8 lore raw

PATCH v2 4/6 arm64: mm: dump: make page table dumping reusable

Quoted 17 lines · Will Deacon

Hi Ard, Mark,

Quoted 7 lines · Ard Biesheuvel

From: Mark Rutland <[email protected]>

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.

Quoted 6 lines
---
 arch/arm64/include/asm/ptdump.h | 44 ++++++++++++++++++++
 arch/arm64/mm/dump.c            | 32 ++++++++------
 2 files changed, 64 insertions(+), 12 deletions(-)
Quoted 3 lines

Could you reorder this with patch 3, please? I'm unsure about the benefit of the very specific string literal changes, but the ptdump stuff here certainly looks beneficial.

I'm sure this is far too late, but for posterity I've rebased patch 4 below atop of pathes 1 & 2 as queued in the arm64 for-next/core branch, without patch 3. It builds cleanly, and I've given it a spin on Juno.

Will, I guess I should rebase and resend this after we hit v4.7-rc1?

Thanks,
Mark.

---->8----

Quoted 1 line

From f17b52c0f004614027c356c848fd21308f4177c1 Mon Sep 17 00:00:00 2001

From: Mark Rutland <[email protected]>
Date: Fri, 22 Apr 2016 18:48:06 +0200
Subject: [PATCH] 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.

---
 arch/arm64/include/asm/ptdump.h | 44 +++++++++++++++++++++++++++++++++++++++++
 arch/arm64/mm/dump.c            | 32 +++++++++++++++++++-----------
 2 files changed, 64 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm64/include/asm/ptdump.h
arch/arm64/include/asm/ptdump.h new file +44 -0
new file mode 100644
index 0000000..07b8ed0
@@ -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 */
arch/arm64/mm/dump.c +20 -12
index 8404190..a56a7ad 100644
@@ -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
@@ -284,7 +280,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;
@@ -303,12 +300,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;
@@ -316,7 +314,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 = {
@@ -326,7 +324,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;
@@ -336,8 +334,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);
Signature · 1 line
1.9.1
#9 lore raw

PATCH v2 4/6 arm64: mm: dump: make page table dumping reusable

Quoted 22 lines · Mark Rutland
Quoted 17 lines · Will Deacon

Hi Ard, Mark,

Quoted 7 lines · Ard Biesheuvel

From: Mark Rutland <[email protected]>

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.

Quoted 6 lines
---
 arch/arm64/include/asm/ptdump.h | 44 ++++++++++++++++++++
 arch/arm64/mm/dump.c            | 32 ++++++++------
 2 files changed, 64 insertions(+), 12 deletions(-)
Quoted 3 lines

Could you reorder this with patch 3, please? I'm unsure about the benefit of the very specific string literal changes, but the ptdump stuff here certainly looks beneficial.

Quoted 6 lines

I'm sure this is far too late, but for posterity I've rebased patch 4 below atop of pathes 1 & 2 as queued in the arm64 for-next/core branch, without patch 3. It builds cleanly, and I've given it a spin on Juno.

Will, I guess I should rebase and resend this after we hit v4.7-rc1?

Yes, please.

Will

#10 lore raw

PATCH v2 5/6 arm: mm: dump: make page table dumping reusable

In reply to Ard Biesheuvel

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 ARM page table dumping code such that multiple tables may be registered with the framework, and exported under debugfs.

(this is a port of Mark Rutland's arm64 patch that does the same)

---
 arch/arm/include/asm/ptdump.h | 44 ++++++++++++++
 arch/arm/mm/dump.c            | 60 ++++++++++++--------
 2 files changed, 81 insertions(+), 23 deletions(-)
arch/arm/include/asm/ptdump.h new file +44 -0
new file mode 100644
index 000000000000..2df5737b2cc7
@@ -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_ARM_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_ARM_PTDUMP */
+
+#endif /* __ASM_PTDUMP_H */
arch/arm/mm/dump.c +37 -23

129 lines not on this page · raw message

Signature · 1 line
2.7.4
#11 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

In reply to Ard Biesheuvel

From: Mark Rutland <[email protected]>

Occasionally it's useful to inspect the page tables used for EFI runtime services, similarly to those cases where it's useful to be able to inspect the kernel page tables.

Now that the kernel page table dump code has been made generic, use it to export the EFI runtime services page tables under debugfs (as "efi_page_tables").

[ ardb: mildly refactored for compatibility with ARM ]
---
 drivers/firmware/efi/arm-runtime.c | 21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)
drivers/firmware/efi/arm-runtime.c +21 -0
index 6ae21e41a429..c48fc2f5413b 100644
@@ -27,6 +27,7 @@
 #include <asm/mmu.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/ptdump.h>
 
 extern u64 efi_system_table;
 
@@ -133,3 +134,23 @@ void efi_virtmap_unload(void)
 	efi_set_pgd(current->active_mm);
 	preempt_enable();
 }
+
+static const struct addr_marker efi_addr_markers[] = {
+	{ 0,	"EFI runtime services" },
+	{ -1 },
+};
+
+static struct ptdump_info efi_ptdump_info = {
+	.mm		= &efi_mm,
+	.markers	= efi_addr_markers,
+	.base_addr	= 0,
+	.max_addr	= SZ_1G,
+};
+
+static int efi_ptdump_init(void)
+{
+	if (!efi_enabled(EFI_RUNTIME_SERVICES))
+		return 0;
+	return ptdump_register(&efi_ptdump_info, "efi_page_tables");
+}
+device_initcall(efi_ptdump_init);
Signature · 1 line
2.7.4
reviewer
#12 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

Quoted 35 lines · Ard Biesheuvel

From: Mark Rutland <[email protected]>

Occasionally it's useful to inspect the page tables used for EFI runtime services, similarly to those cases where it's useful to be able to inspect the kernel page tables.

Now that the kernel page table dump code has been made generic, use it to export the EFI runtime services page tables under debugfs (as "efi_page_tables").

[ ardb: mildly refactored for compatibility with ARM ]
---
 drivers/firmware/efi/arm-runtime.c | 21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)
drivers/firmware/efi/arm-runtime.c +3 -0
index 6ae21e41a429..c48fc2f5413b 100644
@@ -27,6 +27,7 @@
 #include <asm/mmu.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/ptdump.h>
 
 extern u64 efi_system_table;
 
@@ -133,3 +134,23 @@ void efi_virtmap_unload(void)
 	efi_set_pgd(current->active_mm);
 	preempt_enable();
 }
+
+static const struct addr_marker efi_addr_markers[] = {

drivers/firmware/efi/arm-runtime.c void efi_virtmap_unload(void) · line 148

Quoted 10 lines
drivers/firmware/efi/arm-runtime.c +10 -0
+	{ 0,	"EFI runtime services" },
+	{ -1 },
+};
+
+static struct ptdump_info efi_ptdump_info = {
+	.mm		= &efi_mm,
+	.markers	= efi_addr_markers,
+	.base_addr	= 0,
+	.max_addr	= SZ_1G,
+};

I see that max_addr isn't used for arm64, and for ARM it's only used in one place. It doesn't seem great to have that on arm64 given it's unused.

Do we actually need max_addr? Is there any reason not to always dump whole tables?

I guess you're trying to avoid dumping the kernel VA range on 32-bit?

Thanks,
Mark.

Quoted 11 lines
drivers/firmware/efi/arm-runtime.c +8 -0
+
+static int efi_ptdump_init(void)
+{
+	if (!efi_enabled(EFI_RUNTIME_SERVICES))
+		return 0;
+	return ptdump_register(&efi_ptdump_info, "efi_page_tables");
+}
+device_initcall(efi_ptdump_init);
Signature · 1 line
2.7.4
#13 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

Quoted 51 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel

From: Mark Rutland <[email protected]>

Occasionally it's useful to inspect the page tables used for EFI runtime services, similarly to those cases where it's useful to be able to inspect the kernel page tables.

Now that the kernel page table dump code has been made generic, use it to export the EFI runtime services page tables under debugfs (as "efi_page_tables").

[ ardb: mildly refactored for compatibility with ARM ]
---
 drivers/firmware/efi/arm-runtime.c | 21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)
drivers/firmware/efi/arm-runtime.c +3 -0
index 6ae21e41a429..c48fc2f5413b 100644
@@ -27,6 +27,7 @@
 #include <asm/mmu.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/ptdump.h>
 
 extern u64 efi_system_table;
 
@@ -133,3 +134,23 @@ void efi_virtmap_unload(void)
      efi_set_pgd(current->active_mm);
      preempt_enable();
 }
+
+static const struct addr_marker efi_addr_markers[] = {

drivers/firmware/efi/arm-runtime.c void efi_virtmap_unload(void) · line 148

Quoted 10 lines
drivers/firmware/efi/arm-runtime.c +10 -0
+     { 0,    "EFI runtime services" },
+     { -1 },
+};
+
+static struct ptdump_info efi_ptdump_info = {
+     .mm             = &efi_mm,
+     .markers        = efi_addr_markers,
+     .base_addr      = 0,
+     .max_addr       = SZ_1G,
+};

I see that max_addr isn't used for arm64, and for ARM it's only used in one place. It doesn't seem great to have that on arm64 given it's unused.

Quoted 5 lines

Do we actually need max_addr? Is there any reason not to always dump whole tables?

I guess you're trying to avoid dumping the kernel VA range on 32-bit?

Indeed. On ARM, the efi_page_tables dumps its copy of kernel_page_tables. If that is OK (the information could potentially be useful, I suppose) we can drop the max

reviewer
#14 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

Quoted 14 lines · Ard Biesheuvel
Quoted 13 lines · Mark Rutland

drivers/firmware/efi/arm-runtime.c void efi_virtmap_unload(void) · line 148

Quoted 6 lines · Ard Biesheuvel
drivers/firmware/efi/arm-runtime.c +6 -0
+static struct ptdump_info efi_ptdump_info = {
+     .mm             = &efi_mm,
+     .markers        = efi_addr_markers,
+     .base_addr      = 0,
+     .max_addr       = SZ_1G,
+};

I see that max_addr isn't used for arm64, and for ARM it's only used in one place. It doesn't seem great to have that on arm64 given it's unused.

Quoted 8 lines
Quoted 4 lines

Do we actually need max_addr? Is there any reason not to always dump whole tables?

I guess you're trying to avoid dumping the kernel VA range on 32-bit?

Indeed. On ARM, the efi_page_tables dumps its copy of kernel_page_tables. If that is OK (the information could potentially be useful, I suppose) we can drop the max

I'd argue it's always worth dumping the full tables (dropipng the max).

For instance, we could have some bug that leaves the kernel VA range in the EFI tables inconsistent with what we expect/require, and having that exposed would make that clear.

Regardless, arbitrarily limiting the VA range of the arm64 dump doesn't seem great.

Thanks,
Mark.

#15 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

Quoted 24 lines · Mark Rutland
Quoted 14 lines · Ard Biesheuvel
Quoted 13 lines · Mark Rutland

drivers/firmware/efi/arm-runtime.c void efi_virtmap_unload(void) · line 148

Quoted 6 lines · Ard Biesheuvel
drivers/firmware/efi/arm-runtime.c +6 -0
+static struct ptdump_info efi_ptdump_info = {
+     .mm             = &efi_mm,
+     .markers        = efi_addr_markers,
+     .base_addr      = 0,
+     .max_addr       = SZ_1G,
+};

I see that max_addr isn't used for arm64, and for ARM it's only used in one place. It doesn't seem great to have that on arm64 given it's unused.

Quoted 8 lines
Quoted 4 lines

Do we actually need max_addr? Is there any reason not to always dump whole tables?

I guess you're trying to avoid dumping the kernel VA range on 32-bit?

Indeed. On ARM, the efi_page_tables dumps its copy of kernel_page_tables. If that is OK (the information could potentially be useful, I suppose) we can drop the max

Quoted 6 lines

I'd argue it's always worth dumping the full tables (dropipng the max).

For instance, we could have some bug that leaves the kernel VA range in the EFI tables inconsistent with what we expect/require, and having that exposed would make that clear.

Well, the problem here is that we only sync the EFI page tables with the kernel page tables in switch_mm() (if they turn out to be out of sync). This means we should either sync them in this code path as well, or remove the kernel VA range from the output, since we'll be dumping known stale data otherwise.

Quoted 3 lines

Regardless, arbitrarily limiting the VA range of the arm64 dump doesn't seem great.

True. [0 .. TASK_SIZE) looks like a useful and not arbitrary range to limit the EFI page table output to. Unfortunately, TASK_SIZE resolves to a value that depends on TIF_32BIT, so will still need some preprocessor conditional to select between TASK_SIZE_64 (on arm64) and TASK_SIZE (on ARM)

#16 lore raw

PATCH v2 6/6 efi/arm*: add support to dump the EFI page tables

Quoted 5 lines · Ard Biesheuvel

Well, the problem here is that we only sync the EFI page tables with the kernel page tables in switch_mm() (if they turn out to be out of sync). This means we should either sync them in this code path as well, or remove the kernel VA range from the output, since we'll be dumping known stale data otherwise.

The kernel VA range can always be different - even at task switch time we don't always update it. We only update when there's something that needs to be removed from the page table, and we're running on UP systems.

Signature · 3 lines
RMK's Patch system: http://www.arm.linux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
#17 lore raw

v2 cover arm64/ARM pt dumper changes

In reply to Ard Biesheuvel
Quoted 4 lines · Ard Biesheuvel

This series updates the kernel page table dumper to:
- not initialize the vmemmap region markers dynamically
- show region boundaries for the kasan shadow region
- include the UEFI runtime services mappings

I've merged the first two patches of this series. I can take patch 4 too if you can rebase onto for-next/core.

Cheers,

Will

#18 lore raw

v2 cover arm64/ARM pt dumper changes

Quoted 9 lines · Will Deacon
Quoted 4 lines · Ard Biesheuvel

This series updates the kernel page table dumper to:
- not initialize the vmemmap region markers dynamically
- show region boundaries for the kasan shadow region
- include the UEFI runtime services mappings

I've merged the first two patches of this series. I can take patch 4 too if you can rebase onto for-next/core.

Thanks, but it is not very useful without the last patch. I am trying to respin the code so it can be shared between ARM and arm64 in a way that addresses Mark's concerns. But since this is debug code anyway, I am not sure when I will get around to doing that.

Thanks,
Ard.