Commit acc3d3a8 authored by Sebastian Ene's avatar Sebastian Ene Committed by Marc Zyngier

arm64: ptdump: Expose the attribute parsing functionality

Reuse the descriptor parsing functionality to keep the same output format
as the original ptdump code. In order for this to happen, move the state
tracking objects into a common header.

[maz: Fixed note_page() stub as suggested by Will]
Signed-off-by: default avatarSebastian Ene <sebastianene@google.com>
Acked-by: default avatarWill Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20240909124721.1672199-3-sebastianene@google.comSigned-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 29caeda3
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef __ASM_PTDUMP_H #ifndef __ASM_PTDUMP_H
#define __ASM_PTDUMP_H #define __ASM_PTDUMP_H
#include <linux/ptdump.h>
#ifdef CONFIG_PTDUMP_CORE #ifdef CONFIG_PTDUMP_CORE
#include <linux/mm_types.h> #include <linux/mm_types.h>
...@@ -21,14 +23,52 @@ struct ptdump_info { ...@@ -21,14 +23,52 @@ struct ptdump_info {
unsigned long base_addr; unsigned long base_addr;
}; };
struct ptdump_prot_bits {
u64 mask;
u64 val;
const char *set;
const char *clear;
};
struct ptdump_pg_level {
const struct ptdump_prot_bits *bits;
char name[4];
int num;
u64 mask;
};
/*
* The page dumper groups page table entries of the same type into a single
* description. It uses pg_state to track the range information while
* iterating over the pte entries. When the continuity is broken it then
* dumps out a description of the range.
*/
struct ptdump_pg_state {
struct ptdump_state ptdump;
struct seq_file *seq;
const struct addr_marker *marker;
const struct mm_struct *mm;
unsigned long start_address;
int level;
u64 current_prot;
bool check_wx;
unsigned long wx_pages;
unsigned long uxn_pages;
};
void ptdump_walk(struct seq_file *s, struct ptdump_info *info); 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);
#ifdef CONFIG_PTDUMP_DEBUGFS #ifdef CONFIG_PTDUMP_DEBUGFS
#define EFI_RUNTIME_MAP_END DEFAULT_MAP_WINDOW_64 #define EFI_RUNTIME_MAP_END DEFAULT_MAP_WINDOW_64
void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name); void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name);
#else #else
static inline void ptdump_debugfs_register(struct ptdump_info *info, static inline void ptdump_debugfs_register(struct ptdump_info *info,
const char *name) { } const char *name) { }
#endif #endif /* CONFIG_PTDUMP_DEBUGFS */
#else
static inline void note_page(struct ptdump_state *pt_st, unsigned long addr,
int level, u64 val) { }
#endif /* CONFIG_PTDUMP_CORE */ #endif /* CONFIG_PTDUMP_CORE */
#endif /* __ASM_PTDUMP_H */ #endif /* __ASM_PTDUMP_H */
...@@ -38,33 +38,7 @@ ...@@ -38,33 +38,7 @@
seq_printf(m, fmt); \ seq_printf(m, fmt); \
}) })
/* static const struct ptdump_prot_bits pte_bits[] = {
* The page dumper groups page table entries of the same type into a single
* description. It uses pg_state to track the range information while
* iterating over the pte entries. When the continuity is broken it then
* dumps out a description of the range.
*/
struct pg_state {
struct ptdump_state ptdump;
struct seq_file *seq;
const struct addr_marker *marker;
const struct mm_struct *mm;
unsigned long start_address;
int level;
u64 current_prot;
bool check_wx;
unsigned long wx_pages;
unsigned long uxn_pages;
};
struct prot_bits {
u64 mask;
u64 val;
const char *set;
const char *clear;
};
static const struct prot_bits pte_bits[] = {
{ {
.mask = PTE_VALID, .mask = PTE_VALID,
.val = PTE_VALID, .val = PTE_VALID,
...@@ -143,14 +117,7 @@ static const struct prot_bits pte_bits[] = { ...@@ -143,14 +117,7 @@ static const struct prot_bits pte_bits[] = {
} }
}; };
struct pg_level { static struct ptdump_pg_level pg_level[] __ro_after_init = {
const struct prot_bits *bits;
char name[4];
int num;
u64 mask;
};
static struct pg_level pg_level[] __ro_after_init = {
{ /* pgd */ { /* pgd */
.name = "PGD", .name = "PGD",
.bits = pte_bits, .bits = pte_bits,
...@@ -174,7 +141,7 @@ static struct pg_level pg_level[] __ro_after_init = { ...@@ -174,7 +141,7 @@ static struct pg_level pg_level[] __ro_after_init = {
}, },
}; };
static void dump_prot(struct pg_state *st, const struct prot_bits *bits, static void dump_prot(struct ptdump_pg_state *st, const struct ptdump_prot_bits *bits,
size_t num) size_t num)
{ {
unsigned i; unsigned i;
...@@ -192,7 +159,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits, ...@@ -192,7 +159,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
} }
} }
static void note_prot_uxn(struct pg_state *st, unsigned long addr) static void note_prot_uxn(struct ptdump_pg_state *st, unsigned long addr)
{ {
if (!st->check_wx) if (!st->check_wx)
return; return;
...@@ -206,7 +173,7 @@ static void note_prot_uxn(struct pg_state *st, unsigned long addr) ...@@ -206,7 +173,7 @@ static void note_prot_uxn(struct pg_state *st, unsigned long addr)
st->uxn_pages += (addr - st->start_address) / PAGE_SIZE; st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
} }
static void note_prot_wx(struct pg_state *st, unsigned long addr) static void note_prot_wx(struct ptdump_pg_state *st, unsigned long addr)
{ {
if (!st->check_wx) if (!st->check_wx)
return; return;
...@@ -221,10 +188,10 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr) ...@@ -221,10 +188,10 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
st->wx_pages += (addr - st->start_address) / PAGE_SIZE; st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
} }
static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
u64 val) u64 val)
{ {
struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
static const char units[] = "KMGTPE"; static const char units[] = "KMGTPE";
u64 prot = 0; u64 prot = 0;
...@@ -286,12 +253,12 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, ...@@ -286,12 +253,12 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
void ptdump_walk(struct seq_file *s, struct ptdump_info *info) void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
{ {
unsigned long end = ~0UL; unsigned long end = ~0UL;
struct pg_state st; struct ptdump_pg_state st;
if (info->base_addr < TASK_SIZE_64) if (info->base_addr < TASK_SIZE_64)
end = TASK_SIZE_64; end = TASK_SIZE_64;
st = (struct pg_state){ st = (struct ptdump_pg_state){
.seq = s, .seq = s,
.marker = info->markers, .marker = info->markers,
.mm = info->mm, .mm = info->mm,
...@@ -324,7 +291,7 @@ static struct ptdump_info kernel_ptdump_info __ro_after_init = { ...@@ -324,7 +291,7 @@ static struct ptdump_info kernel_ptdump_info __ro_after_init = {
bool ptdump_check_wx(void) bool ptdump_check_wx(void)
{ {
struct pg_state st = { struct ptdump_pg_state st = {
.seq = NULL, .seq = NULL,
.marker = (struct addr_marker[]) { .marker = (struct addr_marker[]) {
{ 0, NULL}, { 0, NULL},
......
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