Commit e064e738 authored by Anshuman Khandual's avatar Anshuman Khandual Committed by Andrew Morton
Browse files

mm/ptdump: split note_page() into level specific callbacks

Patch series "mm/ptdump: Drop assumption that pxd_val() is u64", v2.

Last argument passed down in note_page() is u64 assuming pxd_val()
returned value (all page table levels) is 64 bit - which might not be the
case going ahead when D128 page tables is enabled on arm64 platform. 
Besides pxd_val() is very platform specific and its type should not be
assumed in generic MM.  A similar problem exists for effective_prot(),
although it is restricted to x86 platform.

This series splits note_page() and effective_prot() into individual page
table level specific callbacks which accepts corresponding pxd_t page
table entry as an argument instead and later on all subscribing platforms
could derive pxd_val() from the table entries as required and proceed as
before.

Define ptdesc_t type which describes the basic page table descriptor
layout on arm64 platform.  Subsequently all level specific pxxval_t
descriptors are derived from ptdesc_t thus establishing a common original
format, which can also be appropriate for page table entries, masks and
protection values etc which are used at all page table levels.


This patch (of 3):

Last argument passed down in note_page() is u64 assuming pxd_val()
returned value (all page table levels) is 64 bit - which might not be the
case going ahead when D128 page tables is enabled on arm64 platform. 
Besides pxd_val() is very platform specific and its type should not be
assumed in generic MM.

Split note_page() into individual page table level specific callbacks
which accepts corresponding pxd_t argument instead and then subscribing
platforms just derive pxd_val() from the entries as required and proceed
as earlier.

Also add a note_page_flush() callback for flushing the last page table
page that was being handled earlier via level = -1.

Link: https://lkml.kernel.org/r/20250407053113.746295-1-anshuman.khandual@arm.com
Link: https://lkml.kernel.org/r/20250407053113.746295-2-anshuman.khandual@arm.com


Signed-off-by: default avatarAnshuman Khandual <anshuman.khandual@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent e487a5d5
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -59,7 +59,13 @@ struct ptdump_pg_state {

void ptdump_walk(struct seq_file *s, struct ptdump_info *info);
void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
	       u64 val);
	       pteval_t val);
void note_page_pte(struct ptdump_state *st, unsigned long addr, pte_t pte);
void note_page_pmd(struct ptdump_state *st, unsigned long addr, pmd_t pmd);
void note_page_pud(struct ptdump_state *st, unsigned long addr, pud_t pud);
void note_page_p4d(struct ptdump_state *st, unsigned long addr, p4d_t p4d);
void note_page_pgd(struct ptdump_state *st, unsigned long addr, pgd_t pgd);
void note_page_flush(struct ptdump_state *st);
#ifdef CONFIG_PTDUMP_DEBUGFS
#define EFI_RUNTIME_MAP_END	DEFAULT_MAP_WINDOW_64
void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name);
@@ -69,7 +75,13 @@ static inline void ptdump_debugfs_register(struct ptdump_info *info,
#endif /* CONFIG_PTDUMP_DEBUGFS */
#else
static inline void note_page(struct ptdump_state *pt_st, unsigned long addr,
			     int level, u64 val) { }
			     int level, pteval_t val) { }
static inline void note_page_pte(struct ptdump_state *st, unsigned long addr, pte_t pte) { }
static inline void note_page_pmd(struct ptdump_state *st, unsigned long addr, pmd_t pmd) { }
static inline void note_page_pud(struct ptdump_state *st, unsigned long addr, pud_t pud) { }
static inline void note_page_p4d(struct ptdump_state *st, unsigned long addr, p4d_t p4d) { }
static inline void note_page_pgd(struct ptdump_state *st, unsigned long addr, pgd_t pgd) { }
static inline void note_page_flush(struct ptdump_state *st) { }
#endif /* CONFIG_PTDUMP */

#endif /* __ASM_PTDUMP_H */
+45 −3
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ static void note_prot_wx(struct ptdump_pg_state *st, unsigned long addr)
}

void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
	       u64 val)
	       pteval_t val)
{
	struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
	struct ptdump_pg_level *pg_level = st->pg_level;
@@ -251,6 +251,38 @@ void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,

}

void note_page_pte(struct ptdump_state *pt_st, unsigned long addr, pte_t pte)
{
	note_page(pt_st, addr, 4, pte_val(pte));
}

void note_page_pmd(struct ptdump_state *pt_st, unsigned long addr, pmd_t pmd)
{
	note_page(pt_st, addr, 3, pmd_val(pmd));
}

void note_page_pud(struct ptdump_state *pt_st, unsigned long addr, pud_t pud)
{
	note_page(pt_st, addr, 2, pud_val(pud));
}

void note_page_p4d(struct ptdump_state *pt_st, unsigned long addr, p4d_t p4d)
{
	note_page(pt_st, addr, 1, p4d_val(p4d));
}

void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)
{
	note_page(pt_st, addr, 0, pgd_val(pgd));
}

void note_page_flush(struct ptdump_state *pt_st)
{
	pte_t pte_zero = {0};

	note_page(pt_st, 0, -1, pte_val(pte_zero));
}

void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
{
	unsigned long end = ~0UL;
@@ -266,7 +298,12 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
		.pg_level = &kernel_pg_levels[0],
		.level = -1,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]){
				{info->base_addr, end},
				{0, 0}
@@ -303,7 +340,12 @@ bool ptdump_check_wx(void)
		.level = -1,
		.check_wx = true,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]) {
				{_PAGE_OFFSET(vabits_actual), ~0UL},
				{0, 0}
+44 −2
Original line number Diff line number Diff line
@@ -298,6 +298,38 @@ static void populate_markers(void)
#endif
}

static void note_page_pte(struct ptdump_state *pt_st, unsigned long addr, pte_t pte)
{
	note_page(pt_st, addr, 4, pte_val(pte));
}

static void note_page_pmd(struct ptdump_state *pt_st, unsigned long addr, pmd_t pmd)
{
	note_page(pt_st, addr, 3, pmd_val(pmd));
}

static void note_page_pud(struct ptdump_state *pt_st, unsigned long addr, pud_t pud)
{
	note_page(pt_st, addr, 2, pud_val(pud));
}

static void note_page_p4d(struct ptdump_state *pt_st, unsigned long addr, p4d_t p4d)
{
	note_page(pt_st, addr, 1, p4d_val(p4d));
}

static void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)
{
	note_page(pt_st, addr, 0, pgd_val(pgd));
}

static void note_page_flush(struct ptdump_state *pt_st)
{
	pte_t pte_zero = {0};

	note_page(pt_st, 0, -1, pte_val(pte_zero));
}

static int ptdump_show(struct seq_file *m, void *v)
{
	struct pg_state st = {
@@ -305,7 +337,12 @@ static int ptdump_show(struct seq_file *m, void *v)
		.marker = address_markers,
		.level = -1,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = ptdump_range,
		}
	};
@@ -338,7 +375,12 @@ bool ptdump_check_wx(void)
		.level = -1,
		.check_wx = true,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = ptdump_range,
		}
	};
+44 −2
Original line number Diff line number Diff line
@@ -318,6 +318,38 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr,
	}
}

static void note_page_pte(struct ptdump_state *pt_st, unsigned long addr, pte_t pte)
{
	note_page(pt_st, addr, 4, pte_val(pte));
}

static void note_page_pmd(struct ptdump_state *pt_st, unsigned long addr, pmd_t pmd)
{
	note_page(pt_st, addr, 3, pmd_val(pmd));
}

static void note_page_pud(struct ptdump_state *pt_st, unsigned long addr, pud_t pud)
{
	note_page(pt_st, addr, 2, pud_val(pud));
}

static void note_page_p4d(struct ptdump_state *pt_st, unsigned long addr, p4d_t p4d)
{
	note_page(pt_st, addr, 1, p4d_val(p4d));
}

static void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)
{
	note_page(pt_st, addr, 0, pgd_val(pgd));
}

static void note_page_flush(struct ptdump_state *pt_st)
{
	pte_t pte_zero = {0};

	note_page(pt_st, 0, -1, pte_val(pte_zero));
}

static void ptdump_walk(struct seq_file *s, struct ptd_mm_info *pinfo)
{
	struct pg_state st = {
@@ -325,7 +357,12 @@ static void ptdump_walk(struct seq_file *s, struct ptd_mm_info *pinfo)
		.marker = pinfo->markers,
		.level = -1,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]) {
				{pinfo->base_addr, pinfo->end},
				{0, 0}
@@ -347,7 +384,12 @@ bool ptdump_check_wx(void)
		.level = -1,
		.check_wx = true,
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]) {
				{KERN_VIRT_START, ULONG_MAX},
				{0, 0}
+44 −2
Original line number Diff line number Diff line
@@ -147,11 +147,48 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
	}
}

static void note_page_pte(struct ptdump_state *pt_st, unsigned long addr, pte_t pte)
{
	note_page(pt_st, addr, 4, pte_val(pte));
}

static void note_page_pmd(struct ptdump_state *pt_st, unsigned long addr, pmd_t pmd)
{
	note_page(pt_st, addr, 3, pmd_val(pmd));
}

static void note_page_pud(struct ptdump_state *pt_st, unsigned long addr, pud_t pud)
{
	note_page(pt_st, addr, 2, pud_val(pud));
}

static void note_page_p4d(struct ptdump_state *pt_st, unsigned long addr, p4d_t p4d)
{
	note_page(pt_st, addr, 1, p4d_val(p4d));
}

static void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)
{
	note_page(pt_st, addr, 0, pgd_val(pgd));
}

static void note_page_flush(struct ptdump_state *pt_st)
{
	pte_t pte_zero = {0};

	note_page(pt_st, 0, -1, pte_val(pte_zero));
}

bool ptdump_check_wx(void)
{
	struct pg_state st = {
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]) {
				{.start = 0, .end = max_addr},
				{.start = 0, .end = 0},
@@ -190,7 +227,12 @@ static int ptdump_show(struct seq_file *m, void *v)
{
	struct pg_state st = {
		.ptdump = {
			.note_page = note_page,
			.note_page_pte = note_page_pte,
			.note_page_pmd = note_page_pmd,
			.note_page_pud = note_page_pud,
			.note_page_p4d = note_page_p4d,
			.note_page_pgd = note_page_pgd,
			.note_page_flush = note_page_flush,
			.range = (struct ptdump_range[]) {
				{.start = 0, .end = max_addr},
				{.start = 0, .end = 0},
Loading