linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables
@ 2024-09-09 12:47 Sebastian Ene
  2024-09-09 12:47 ` [PATCH v10 1/5] KVM: arm64: Move pagetable definitions to common header Sebastian Ene
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

Hi,


This series extends the ptdump support to allow dumping the guest
stage-2 pagetables. When CONFIG_PTDUMP_STAGE2_DEBUGFS is enabled, ptdump
registers the new following files under debugfs:
- /sys/debug/kvm/<guest_id>/stage2_page_tables
- /sys/debug/kvm/<guest_id>/stage2_levels
- /sys/debug/kvm/<guest_id>/ipa_range

This allows userspace tools (eg. cat) to dump the stage-2 pagetables by
reading the 'stage2_page_tables' file.
The output format has the following fields:
<IPA range> <size> <level> <access permissions> <mem_attributes>

Below is the output of a guest stage-2 pagetable dump running under Qemu.
After a VM is created, the following files are available:

# cat /sys/kernel/debug/kvm/256-4/stage2_levels 
4
# cat /sys/kernel/debug/kvm/256-4/ipa_range 
44
# cat /sys/kernel/debug/kvm/256-4/stage2_page_tables 
---[ Guest IPA ]---
0x0000000000000000-0x0000000001000000          16M 2
0x0000000001000000-0x0000000001020000         128K 3
0x0000000001020000-0x0000000001021000           4K 3   R W X AF    
0x0000000001021000-0x0000000001200000        1916K 3
0x0000000001200000-0x0000000040000000        1006M 2
0x0000000040000000-0x0000000080000000           1G 0
0x0000000080000000-0x0000000081200000          18M 2   R W   AF BLK
0x0000000081200000-0x0000000081a00000           8M 2   R W X AF BLK
0x0000000081a00000-0x0000000081c00000           2M 2   R W   AF BLK
0x0000000081c00000-0x0000000082200000           6M 2   R W X AF BLK
0x0000000082200000-0x0000000082400000           2M 2   R W   AF BLK
0x0000000082400000-0x0000000082800000           4M 2   R W X AF BLK
0x0000000082800000-0x0000000082a00000           2M 2   R W   AF BLK
0x0000000082a00000-0x0000000082c00000           2M 2
0x0000000082c00000-0x0000000083200000           6M 2   R W X AF BLK
0x0000000083200000-0x0000000083400000           2M 2
0x0000000083400000-0x0000000083a00000           6M 2   R W X AF BLK
0x0000000083a00000-0x000000008fe00000         196M 2
0x000000008fe00000-0x0000000090000000           2M 2   R W   AF BLK
0x0000000090000000-0x0000000099400000         148M 2
0x0000000099400000-0x0000000099600000           2M 2   R W X AF BLK
0x0000000099600000-0x000000009b600000          32M 2
0x000000009b600000-0x000000009be00000           8M 2   R W X AF BLK
0x000000009be00000-0x000000009c000000           2M 2   R W   AF BLK
0x000000009c000000-0x00000000c0000000         576M 2

Changelog:
v9 -> current:
 * fixed an issue reported by Mark - when using CONFIG_ARM64_VA_BITS=47
   and CONFIG_PAGE_SIZE_16KB=y ptdump was entering a check used for
   kernel pagetables to interpret the folded levels, thus overriding the
   current page table level. This was resulting in bogus output when ran
   on the stage-2 pagetables. 

 * folded the Kconfig patch in the one that introduces kvm/ptdump.c as
   suggested by Vincent. Collected Vincent's Reviewed-by tag, thanks.

 * applied Mark's sugegstion to use the callbacks by construct when
   interpretting the level and the ipa_bits instead of a string
   comparison on the pseudo-file.

 * fixed a bunch of nits

v8 -> v9:
 * squashed the last 3 patches and separated the Kconfig change as the
   last patch.
 * updated the commit message of the 3rd patch
 * printing level numbers instead of names as suggested by Mark
 * fixed one return code to ERR_PTR(-ENOMEM) as spotted by Vincent
 * dropped a barely empty header 'kvm_ptdump.h'
 * general cosmetic changes 

v7 -> v8:
 * applied Will's feedback and prefixed the exported structure names
   with ptdump_
 * dropped PTE_CONT and PTE_NG attribute parsing from Oliver's
   suggestion
 * fixed spurious BLK annotation reported by Vincent
 * repurposed `stage2_levels` debugfs file to show the number of the
   levels
 * tried changing the order of the patches:
   "5/6 Initialize the ptdump parser with stage-2 attributes" before
   exposing the debugfs file but ended up keeping the same order
   as this depends on the later one.

 v6 -> v7:
 * Reworded commit for this patch : [PATCH v6 2/6] arm64: ptdump: Expose
   the attribute parsing functionality
 * fixed minor conflicts in the struct pg_state definition
 * moved the kvm_ptdump_guest_registration in the
 * kvm_arch_create_vm_debugfs
 * reset the parse state before walking the pagetables
 * copy the level name to the pg_level buffer

 v5 -> v6:
 * don't return an error if the kvm_arch_create_vm_debugfs fails to
   initialize (ref.
https://lore.kernel.org/all/20240216155941.2029458-1-oliver.upton@linux.dev/)  
 * fix use-after-free suggested by getting a reference to the
   KVM struct while manipulating the debugfs files
   and put the reference on the file close.
 * do all the allocations at once for the ptdump parser state tracking
   and simplify the initialization.
 * move the ptdump parser state initialization as part of the file_open
 * create separate files for printing the guest stage-2 pagetable
   configuration such as: the start level of the pagetable walk and the
   number of bits used for the IPA space representation.
 * fixed the wrong header format for the newly added file
 * include missing patch which hasn't been posted on the v5:
   "KVM-arm64-Move-pagetable-definitions-to-common-heade.patch" 

 
Links to previous versions:
v9:
https://lore.kernel.org/all/20240827084549.45731-1-sebastianene@google.com/
v8:
https://lore.kernel.org/all/20240816123906.3683425-1-sebastianene@google.com/  
v7:
https://lore.kernel.org/all/20240621123230.1085265-1-sebastianene@google.com/
v6:
https://lore.kernel.org/all/20240220151035.327199-1-sebastianene@google.com/
v5:
https://lore.kernel.org/all/20240207144832.1017815-2-sebastianene@google.com/

Thanks,
Sebastian

Sebastian Ene (5):
  KVM: arm64: Move pagetable definitions to common header
  arm64: ptdump: Expose the attribute parsing functionality
  arm64: ptdump: Use the ptdump description from a local context
  arm64: ptdump: Don't override the level when operating on the stage-2
    tables
  KVM: arm64: Register ptdump with debugfs on guest creation

 arch/arm64/include/asm/kvm_host.h    |   6 +
 arch/arm64/include/asm/kvm_pgtable.h |  42 +++++
 arch/arm64/include/asm/ptdump.h      |  42 ++++-
 arch/arm64/kvm/Kconfig               |  17 ++
 arch/arm64/kvm/Makefile              |   1 +
 arch/arm64/kvm/arm.c                 |   1 +
 arch/arm64/kvm/hyp/pgtable.c         |  42 -----
 arch/arm64/kvm/ptdump.c              | 268 +++++++++++++++++++++++++++
 arch/arm64/mm/ptdump.c               |  70 ++-----
 9 files changed, 396 insertions(+), 93 deletions(-)
 create mode 100644 arch/arm64/kvm/ptdump.c

-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v10 1/5] KVM: arm64: Move pagetable definitions to common header
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
@ 2024-09-09 12:47 ` Sebastian Ene
  2024-09-09 12:47 ` [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality Sebastian Ene
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

In preparation for using the stage-2 definitions in ptdump, move some of
these macros in the common header.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/include/asm/kvm_pgtable.h | 42 ++++++++++++++++++++++++++++
 arch/arm64/kvm/hyp/pgtable.c         | 42 ----------------------------
 2 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 19278dfe7978..03f4c3d7839c 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -59,6 +59,48 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PHYS_INVALID		(-1ULL)
 
+#define KVM_PTE_LEAF_ATTR_LO		GENMASK(11, 2)
+
+#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX	GENMASK(4, 2)
+#define KVM_PTE_LEAF_ATTR_LO_S1_AP	GENMASK(7, 6)
+#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO		\
+	({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; })
+#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW		\
+	({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })
+#define KVM_PTE_LEAF_ATTR_LO_S1_SH	GENMASK(9, 8)
+#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS	3
+#define KVM_PTE_LEAF_ATTR_LO_S1_AF	BIT(10)
+
+#define KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR	GENMASK(5, 2)
+#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R	BIT(6)
+#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W	BIT(7)
+#define KVM_PTE_LEAF_ATTR_LO_S2_SH	GENMASK(9, 8)
+#define KVM_PTE_LEAF_ATTR_LO_S2_SH_IS	3
+#define KVM_PTE_LEAF_ATTR_LO_S2_AF	BIT(10)
+
+#define KVM_PTE_LEAF_ATTR_HI		GENMASK(63, 50)
+
+#define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
+
+#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
+
+#define KVM_PTE_LEAF_ATTR_HI_S2_XN	BIT(54)
+
+#define KVM_PTE_LEAF_ATTR_HI_S1_GP	BIT(50)
+
+#define KVM_PTE_LEAF_ATTR_S2_PERMS	(KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
+					 KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \
+					 KVM_PTE_LEAF_ATTR_HI_S2_XN)
+
+#define KVM_INVALID_PTE_OWNER_MASK	GENMASK(9, 2)
+#define KVM_MAX_OWNER_ID		1
+
+/*
+ * Used to indicate a pte for which a 'break-before-make' sequence is in
+ * progress.
+ */
+#define KVM_INVALID_PTE_LOCKED		BIT(10)
+
 static inline bool kvm_pte_valid(kvm_pte_t pte)
 {
 	return pte & KVM_PTE_VALID;
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 9e2bbee77491..c3e9d77bba23 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -17,48 +17,6 @@
 #define KVM_PTE_TYPE_PAGE		1
 #define KVM_PTE_TYPE_TABLE		1
 
-#define KVM_PTE_LEAF_ATTR_LO		GENMASK(11, 2)
-
-#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX	GENMASK(4, 2)
-#define KVM_PTE_LEAF_ATTR_LO_S1_AP	GENMASK(7, 6)
-#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO		\
-	({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; })
-#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW		\
-	({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })
-#define KVM_PTE_LEAF_ATTR_LO_S1_SH	GENMASK(9, 8)
-#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS	3
-#define KVM_PTE_LEAF_ATTR_LO_S1_AF	BIT(10)
-
-#define KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR	GENMASK(5, 2)
-#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R	BIT(6)
-#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W	BIT(7)
-#define KVM_PTE_LEAF_ATTR_LO_S2_SH	GENMASK(9, 8)
-#define KVM_PTE_LEAF_ATTR_LO_S2_SH_IS	3
-#define KVM_PTE_LEAF_ATTR_LO_S2_AF	BIT(10)
-
-#define KVM_PTE_LEAF_ATTR_HI		GENMASK(63, 50)
-
-#define KVM_PTE_LEAF_ATTR_HI_SW		GENMASK(58, 55)
-
-#define KVM_PTE_LEAF_ATTR_HI_S1_XN	BIT(54)
-
-#define KVM_PTE_LEAF_ATTR_HI_S2_XN	BIT(54)
-
-#define KVM_PTE_LEAF_ATTR_HI_S1_GP	BIT(50)
-
-#define KVM_PTE_LEAF_ATTR_S2_PERMS	(KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
-					 KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \
-					 KVM_PTE_LEAF_ATTR_HI_S2_XN)
-
-#define KVM_INVALID_PTE_OWNER_MASK	GENMASK(9, 2)
-#define KVM_MAX_OWNER_ID		1
-
-/*
- * Used to indicate a pte for which a 'break-before-make' sequence is in
- * progress.
- */
-#define KVM_INVALID_PTE_LOCKED		BIT(10)
-
 struct kvm_pgtable_walk_data {
 	struct kvm_pgtable_walker	*walker;
 
-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
  2024-09-09 12:47 ` [PATCH v10 1/5] KVM: arm64: Move pagetable definitions to common header Sebastian Ene
@ 2024-09-09 12:47 ` Sebastian Ene
  2024-09-10  9:57   ` Will Deacon
  2024-09-09 12:47 ` [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context Sebastian Ene
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

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.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/include/asm/ptdump.h | 41 +++++++++++++++++++++++-
 arch/arm64/mm/ptdump.c          | 55 +++++++--------------------------
 2 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 5b1701c76d1c..bd5d3ee3e8dc 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -9,6 +9,7 @@
 
 #include <linux/mm_types.h>
 #include <linux/seq_file.h>
+#include <linux/ptdump.h>
 
 struct addr_marker {
 	unsigned long start_address;
@@ -21,14 +22,52 @@ struct ptdump_info {
 	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 note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
+	       u64 val);
 #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);
 #else
 static inline void ptdump_debugfs_register(struct ptdump_info *info,
 					   const char *name) { }
-#endif
+#endif /* CONFIG_PTDUMP_DEBUGFS */
+#else
+static inline void note_page(void *pt_st, unsigned long addr,
+			     int level, u64 val) { }
 #endif /* CONFIG_PTDUMP_CORE */
 
 #endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
index 6986827e0d64..404751fd30fe 100644
--- a/arch/arm64/mm/ptdump.c
+++ b/arch/arm64/mm/ptdump.c
@@ -38,33 +38,7 @@
 		seq_printf(m, fmt);	\
 })
 
-/*
- * 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[] = {
+static const struct ptdump_prot_bits pte_bits[] = {
 	{
 		.mask	= PTE_VALID,
 		.val	= PTE_VALID,
@@ -143,14 +117,7 @@ static const struct prot_bits pte_bits[] = {
 	}
 };
 
-struct pg_level {
-	const struct prot_bits *bits;
-	char name[4];
-	int num;
-	u64 mask;
-};
-
-static struct pg_level pg_level[] __ro_after_init = {
+static struct ptdump_pg_level pg_level[] __ro_after_init = {
 	{ /* pgd */
 		.name	= "PGD",
 		.bits	= pte_bits,
@@ -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)
 {
 	unsigned i;
@@ -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)
 		return;
@@ -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;
 }
 
-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)
 		return;
@@ -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;
 }
 
-static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
-		      u64 val)
+void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
+	       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";
 	u64 prot = 0;
 
@@ -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)
 {
 	unsigned long end = ~0UL;
-	struct pg_state st;
+	struct ptdump_pg_state st;
 
 	if (info->base_addr < TASK_SIZE_64)
 		end = TASK_SIZE_64;
 
-	st = (struct pg_state){
+	st = (struct ptdump_pg_state){
 		.seq = s,
 		.marker = info->markers,
 		.mm = info->mm,
@@ -324,7 +291,7 @@ static struct ptdump_info kernel_ptdump_info __ro_after_init = {
 
 bool ptdump_check_wx(void)
 {
-	struct pg_state st = {
+	struct ptdump_pg_state st = {
 		.seq = NULL,
 		.marker = (struct addr_marker[]) {
 			{ 0, NULL},
-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
  2024-09-09 12:47 ` [PATCH v10 1/5] KVM: arm64: Move pagetable definitions to common header Sebastian Ene
  2024-09-09 12:47 ` [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality Sebastian Ene
@ 2024-09-09 12:47 ` Sebastian Ene
  2024-09-10 10:03   ` Will Deacon
  2024-09-09 12:47 ` [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables Sebastian Ene
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

Rename the attributes description array to allow the parsing method
to use the description from a local context. To be able to do this,
store a pointer to the description array in the state structure. This
will allow for the later introduced callers (stage_2 ptdump) to specify
their own page table description format to the ptdump parser.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/include/asm/ptdump.h |  1 +
 arch/arm64/mm/ptdump.c          | 13 ++++++++-----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index bd5d3ee3e8dc..71a7ed01153a 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -44,6 +44,7 @@ struct ptdump_pg_level {
  */
 struct ptdump_pg_state {
 	struct ptdump_state ptdump;
+	struct ptdump_pg_level *pg_level;
 	struct seq_file *seq;
 	const struct addr_marker *marker;
 	const struct mm_struct *mm;
diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
index 404751fd30fe..ca53ef274a8b 100644
--- a/arch/arm64/mm/ptdump.c
+++ b/arch/arm64/mm/ptdump.c
@@ -117,7 +117,7 @@ static const struct ptdump_prot_bits pte_bits[] = {
 	}
 };
 
-static struct ptdump_pg_level pg_level[] __ro_after_init = {
+static struct ptdump_pg_level kernel_pg_levels[] __ro_after_init = {
 	{ /* pgd */
 		.name	= "PGD",
 		.bits	= pte_bits,
@@ -192,6 +192,7 @@ void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
 	       u64 val)
 {
 	struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
+	struct ptdump_pg_level *pg_level = st->pg_level;
 	static const char units[] = "KMGTPE";
 	u64 prot = 0;
 
@@ -262,6 +263,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
 		.seq = s,
 		.marker = info->markers,
 		.mm = info->mm,
+		.pg_level = &kernel_pg_levels[0],
 		.level = -1,
 		.ptdump = {
 			.note_page = note_page,
@@ -279,10 +281,10 @@ static void __init ptdump_initialize(void)
 {
 	unsigned i, j;
 
-	for (i = 0; i < ARRAY_SIZE(pg_level); i++)
-		if (pg_level[i].bits)
-			for (j = 0; j < pg_level[i].num; j++)
-				pg_level[i].mask |= pg_level[i].bits[j].mask;
+	for (i = 0; i < ARRAY_SIZE(kernel_pg_levels); i++)
+		if (kernel_pg_levels[i].bits)
+			for (j = 0; j < kernel_pg_levels[i].num; j++)
+				kernel_pg_levels[i].mask |= kernel_pg_levels[i].bits[j].mask;
 }
 
 static struct ptdump_info kernel_ptdump_info __ro_after_init = {
@@ -297,6 +299,7 @@ bool ptdump_check_wx(void)
 			{ 0, NULL},
 			{ -1, NULL},
 		},
+		.pg_level = &kernel_pg_levels[0],
 		.level = -1,
 		.check_wx = true,
 		.ptdump = {
-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
                   ` (2 preceding siblings ...)
  2024-09-09 12:47 ` [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context Sebastian Ene
@ 2024-09-09 12:47 ` Sebastian Ene
  2024-09-10 10:05   ` Will Deacon
  2024-09-09 12:47 ` [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation Sebastian Ene
  2024-09-10 20:35 ` [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Marc Zyngier
  5 siblings, 1 reply; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

Ptdump uses the init_mm structure directly to dump the kernel
pagetables. When ptdump is called on the stage-2 pagetables, this mm
argument is not used. Prevent the level from being overwritten by
checking the argument against NULL.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/mm/ptdump.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c
index ca53ef274a8b..264c5f9b97d8 100644
--- a/arch/arm64/mm/ptdump.c
+++ b/arch/arm64/mm/ptdump.c
@@ -197,8 +197,8 @@ void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
 	u64 prot = 0;
 
 	/* check if the current level has been folded dynamically */
-	if ((level == 1 && mm_p4d_folded(st->mm)) ||
-	    (level == 2 && mm_pud_folded(st->mm)))
+	if (st->mm && ((level == 1 && mm_p4d_folded(st->mm)) ||
+	    (level == 2 && mm_pud_folded(st->mm))))
 		level = 0;
 
 	if (level >= 0)
-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
                   ` (3 preceding siblings ...)
  2024-09-09 12:47 ` [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables Sebastian Ene
@ 2024-09-09 12:47 ` Sebastian Ene
  2024-09-10 20:27   ` Marc Zyngier
  2024-09-10 20:35 ` [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Marc Zyngier
  5 siblings, 1 reply; 12+ messages in thread
From: Sebastian Ene @ 2024-09-09 12:47 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, sebastianene, shahuang, suzuki.poulose, will,
	yuzenghui
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

While arch/*/mem/ptdump handles the kernel pagetable dumping code,
introduce KVM/ptdump to show the guest stage-2 pagetables. The
separation is necessary because most of the definitions from the
stage-2 pagetable reside in the KVM path and we will be invoking
functionality specific to KVM. Introduce the PTDUMP_STAGE2_DEBUGFS config.

When a guest is created, register a new file entry under the guest
debugfs dir which allows userspace to show the contents of the guest
stage-2 pagetables when accessed.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
---
 arch/arm64/include/asm/kvm_host.h |   6 +
 arch/arm64/kvm/Kconfig            |  17 ++
 arch/arm64/kvm/Makefile           |   1 +
 arch/arm64/kvm/arm.c              |   1 +
 arch/arm64/kvm/ptdump.c           | 268 ++++++++++++++++++++++++++++++
 5 files changed, 293 insertions(+)
 create mode 100644 arch/arm64/kvm/ptdump.c

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a33f5996ca9f..4acd589f086b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1473,4 +1473,10 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
 		(pa + pi + pa3) == 1;					\
 	})
 
+#ifdef CONFIG_PTDUMP_STAGE2_DEBUGFS
+void kvm_s2_ptdump_create_debugfs(struct kvm *kvm);
+#else
+static inline void kvm_s2_ptdump_create_debugfs(struct kvm *kvm) {}
+#endif /* CONFIG_PTDUMP_STAGE2_DEBUGFS */
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 8304eb342be9..ead632ad01b4 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -66,4 +66,21 @@ config PROTECTED_NVHE_STACKTRACE
 
 	  If unsure, or not using protected nVHE (pKVM), say N.
 
+config PTDUMP_STAGE2_DEBUGFS
+	bool "Present the stage-2 pagetables to debugfs"
+	depends on KVM
+	depends on DEBUG_KERNEL
+	depends on DEBUG_FS
+	depends on GENERIC_PTDUMP
+	select PTDUMP_CORE
+	default n
+	help
+	  Say Y here if you want to show the stage-2 kernel pagetables
+	  layout in a debugfs file. This information is only useful for kernel developers
+	  who are working in architecture specific areas of the kernel.
+	  It is probably not a good idea to enable this feature in a production
+	  kernel.
+
+	  If in doubt, say N.
+
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 86a629aaf0a1..e4233b323a73 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -27,6 +27,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 
 kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 kvm-$(CONFIG_ARM64_PTR_AUTH)  += pauth.o
+kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o
 
 always-y := hyp_constants.h hyp-constants.s
 
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 9bef7638342e..b9fd928d3477 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -228,6 +228,7 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 void kvm_arch_create_vm_debugfs(struct kvm *kvm)
 {
 	kvm_sys_regs_create_debugfs(kvm);
+	kvm_s2_ptdump_create_debugfs(kvm);
 }
 
 static void kvm_destroy_mpidr_data(struct kvm *kvm)
diff --git a/arch/arm64/kvm/ptdump.c b/arch/arm64/kvm/ptdump.c
new file mode 100644
index 000000000000..e29604a864b7
--- /dev/null
+++ b/arch/arm64/kvm/ptdump.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Debug helper used to dump the stage-2 pagetables of the system and their
+ * associated permissions.
+ *
+ * Copyright (C) Google, 2024
+ * Author: Sebastian Ene <sebastianene@google.com>
+ */
+#include <linux/debugfs.h>
+#include <linux/kvm_host.h>
+#include <linux/seq_file.h>
+
+#include <asm/kvm_host.h>
+#include <asm/kvm_pgtable.h>
+#include <asm/ptdump.h>
+
+#define MARKERS_LEN		2
+#define KVM_PGTABLE_MAX_LEVELS	(KVM_PGTABLE_LAST_LEVEL + 1)
+
+struct kvm_ptdump_guest_state {
+	struct kvm		*kvm;
+	struct ptdump_pg_state	parser_state;
+	struct addr_marker	ipa_marker[MARKERS_LEN];
+	struct ptdump_pg_level	level[KVM_PGTABLE_MAX_LEVELS];
+	struct ptdump_range	range[MARKERS_LEN];
+};
+
+static const struct ptdump_prot_bits stage2_pte_bits[] = {
+	{
+		.mask	= PTE_VALID,
+		.val	= PTE_VALID,
+		.set	= " ",
+		.clear	= "F",
+	}, {
+		.mask	= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID,
+		.val	= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID,
+		.set	= "R",
+		.clear	= " ",
+	}, {
+		.mask	= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID,
+		.val	= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID,
+		.set	= "W",
+		.clear	= " ",
+	}, {
+		.mask	= KVM_PTE_LEAF_ATTR_HI_S2_XN | PTE_VALID,
+		.val	= PTE_VALID,
+		.set	= " ",
+		.clear	= "X",
+	}, {
+		.mask	= KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID,
+		.val	= KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID,
+		.set	= "AF",
+		.clear	= "  ",
+	}, {
+		.mask	= PTE_TABLE_BIT | PTE_VALID,
+		.val	= PTE_VALID,
+		.set	= "BLK",
+		.clear	= "   ",
+	},
+};
+
+static int kvm_ptdump_visitor(const struct kvm_pgtable_visit_ctx *ctx,
+			      enum kvm_pgtable_walk_flags visit)
+{
+	struct ptdump_pg_state *st = ctx->arg;
+	struct ptdump_state *pt_st = &st->ptdump;
+
+	note_page(pt_st, ctx->addr, ctx->level, ctx->old);
+
+	return 0;
+}
+
+static int kvm_ptdump_build_levels(struct ptdump_pg_level *level, u32 start_lvl)
+{
+	u32 i;
+	u64 mask;
+
+	if (WARN_ON_ONCE(start_lvl >= KVM_PGTABLE_LAST_LEVEL))
+		return -EINVAL;
+
+	mask = 0;
+	for (i = 0; i < ARRAY_SIZE(stage2_pte_bits); i++)
+		mask |= stage2_pte_bits[i].mask;
+
+	for (i = start_lvl; i < KVM_PGTABLE_MAX_LEVELS; i++) {
+		snprintf(level[i].name, sizeof(level[i].name), "%u", i);
+
+		level[i].num	= ARRAY_SIZE(stage2_pte_bits);
+		level[i].bits	= stage2_pte_bits;
+		level[i].mask	= mask;
+	}
+
+	return 0;
+}
+
+static struct kvm_ptdump_guest_state *kvm_ptdump_parser_create(struct kvm *kvm)
+{
+	struct kvm_ptdump_guest_state *st;
+	struct kvm_s2_mmu *mmu = &kvm->arch.mmu;
+	struct kvm_pgtable *pgtable = mmu->pgt;
+	int ret;
+
+	st = kzalloc(sizeof(struct kvm_ptdump_guest_state), GFP_KERNEL_ACCOUNT);
+	if (!st)
+		return ERR_PTR(-ENOMEM);
+
+	ret = kvm_ptdump_build_levels(&st->level[0], pgtable->start_level);
+	if (ret) {
+		kfree(st);
+		return ERR_PTR(ret);
+	}
+
+	st->ipa_marker[0].name		= "Guest IPA";
+	st->ipa_marker[1].start_address = BIT(pgtable->ia_bits);
+	st->range[0].end		= BIT(pgtable->ia_bits);
+
+	st->kvm				= kvm;
+	st->parser_state = (struct ptdump_pg_state) {
+		.marker		= &st->ipa_marker[0],
+		.level		= -1,
+		.pg_level	= &st->level[0],
+		.ptdump.range	= &st->range[0],
+		.start_address	= 0,
+	};
+
+	return st;
+}
+
+static int kvm_ptdump_guest_show(struct seq_file *m, void *unused)
+{
+	int ret;
+	struct kvm_ptdump_guest_state *st = m->private;
+	struct kvm *kvm = st->kvm;
+	struct kvm_s2_mmu *mmu = &kvm->arch.mmu;
+	struct ptdump_pg_state *parser_state = &st->parser_state;
+	struct kvm_pgtable_walker walker = (struct kvm_pgtable_walker) {
+		.cb	= kvm_ptdump_visitor,
+		.arg	= parser_state,
+		.flags	= KVM_PGTABLE_WALK_LEAF,
+	};
+
+	parser_state->seq = m;
+
+	write_lock(&kvm->mmu_lock);
+	ret = kvm_pgtable_walk(mmu->pgt, 0, BIT(mmu->pgt->ia_bits), &walker);
+	write_unlock(&kvm->mmu_lock);
+
+	return ret;
+}
+
+static int kvm_ptdump_guest_open(struct inode *m, struct file *file)
+{
+	struct kvm *kvm = m->i_private;
+	struct kvm_ptdump_guest_state *st;
+	int ret;
+
+	if (!kvm_get_kvm_safe(kvm))
+		return -ENOENT;
+
+	st = kvm_ptdump_parser_create(kvm);
+	if (IS_ERR(st)) {
+		ret = PTR_ERR(st);
+		goto err_with_kvm_ref;
+	}
+
+	ret = single_open(file, kvm_ptdump_guest_show, st);
+	if (!ret)
+		return 0;
+
+	kfree(st);
+err_with_kvm_ref:
+	kvm_put_kvm(kvm);
+	return ret;
+}
+
+static int kvm_ptdump_guest_close(struct inode *m, struct file *file)
+{
+	struct kvm *kvm = m->i_private;
+	void *st = ((struct seq_file *)file->private_data)->private;
+
+	kfree(st);
+	kvm_put_kvm(kvm);
+
+	return single_release(m, file);
+}
+
+static const struct file_operations kvm_ptdump_guest_fops = {
+	.open		= kvm_ptdump_guest_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= kvm_ptdump_guest_close,
+};
+
+static int kvm_pgtable_range_show(struct seq_file *m, void *unused)
+{
+	struct kvm_pgtable *pgtable = m->private;
+
+	seq_printf(m, "%2u\n", pgtable->ia_bits);
+	return 0;
+}
+
+static int kvm_pgtable_levels_show(struct seq_file *m, void *unused)
+{
+	struct kvm_pgtable *pgtable = m->private;
+
+	seq_printf(m, "%1d\n", KVM_PGTABLE_MAX_LEVELS - pgtable->start_level);
+	return 0;
+}
+
+static int kvm_pgtable_debugfs_open(struct inode *m, struct file *file,
+				    int (*show)(struct seq_file *, void *))
+{
+	struct kvm *kvm = m->i_private;
+	struct kvm_pgtable *pgtable;
+	int ret;
+
+	if (!kvm_get_kvm_safe(kvm))
+		return -ENOENT;
+
+	pgtable = kvm->arch.mmu.pgt;
+
+	ret = single_open(file, show, pgtable);
+	if (ret < 0)
+		kvm_put_kvm(kvm);
+	return ret;
+}
+
+static int kvm_pgtable_range_open(struct inode *m, struct file *file)
+{
+	return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_range_show);
+}
+
+static int kvm_pgtable_levels_open(struct inode *m, struct file *file)
+{
+	return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_levels_show);
+}
+
+static int kvm_pgtable_debugfs_close(struct inode *m, struct file *file)
+{
+	struct kvm *kvm = m->i_private;
+
+	kvm_put_kvm(kvm);
+	return single_release(m, file);
+}
+
+static const struct file_operations kvm_pgtable_range_fops = {
+	.open		= kvm_pgtable_range_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= kvm_pgtable_debugfs_close,
+};
+
+static const struct file_operations kvm_pgtable_levels_fops = {
+	.open		= kvm_pgtable_levels_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= kvm_pgtable_debugfs_close,
+};
+
+void kvm_s2_ptdump_create_debugfs(struct kvm *kvm)
+{
+	debugfs_create_file("stage2_page_tables", 0400, kvm->debugfs_dentry,
+			    kvm, &kvm_ptdump_guest_fops);
+	debugfs_create_file("ipa_range", 0400, kvm->debugfs_dentry, kvm,
+			    &kvm_pgtable_range_fops);
+	debugfs_create_file("stage2_levels", 0400, kvm->debugfs_dentry,
+			    kvm, &kvm_pgtable_levels_fops);
+}
-- 
2.46.0.469.g59c65b2a67-goog



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality
  2024-09-09 12:47 ` [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality Sebastian Ene
@ 2024-09-10  9:57   ` Will Deacon
  2024-09-10 16:59     ` Marc Zyngier
  0 siblings, 1 reply; 12+ messages in thread
From: Will Deacon @ 2024-09-10  9:57 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, shahuang, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, linux-kernel, kernel-team

On Mon, Sep 09, 2024 at 12:47:18PM +0000, Sebastian Ene wrote:
> 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.
> 
> Signed-off-by: Sebastian Ene <sebastianene@google.com>
> ---
>  arch/arm64/include/asm/ptdump.h | 41 +++++++++++++++++++++++-
>  arch/arm64/mm/ptdump.c          | 55 +++++++--------------------------
>  2 files changed, 51 insertions(+), 45 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
> index 5b1701c76d1c..bd5d3ee3e8dc 100644
> --- a/arch/arm64/include/asm/ptdump.h
> +++ b/arch/arm64/include/asm/ptdump.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/mm_types.h>
>  #include <linux/seq_file.h>
> +#include <linux/ptdump.h>
>  
>  struct addr_marker {
>  	unsigned long start_address;
> @@ -21,14 +22,52 @@ struct ptdump_info {
>  	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 note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
> +	       u64 val);
>  #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);
>  #else
>  static inline void ptdump_debugfs_register(struct ptdump_info *info,
>  					   const char *name) { }
> -#endif
> +#endif /* CONFIG_PTDUMP_DEBUGFS */
> +#else
> +static inline void note_page(void *pt_st, unsigned long addr,
> +			     int level, u64 val) { }

nit: but why isn't 'pt_st' a pointer to 'struct ptdump_state'?

Perhaps you should #include <linux/ptdump.h> before the #ifdef
CONFIG_PTDUMP_CORE ?

In any case, the meat of the patch is fine:

Acked-by: Will Deacon <will@kernel.org>

Will


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context
  2024-09-09 12:47 ` [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context Sebastian Ene
@ 2024-09-10 10:03   ` Will Deacon
  0 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2024-09-10 10:03 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, shahuang, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, linux-kernel, kernel-team

On Mon, Sep 09, 2024 at 12:47:19PM +0000, Sebastian Ene wrote:
> Rename the attributes description array to allow the parsing method
> to use the description from a local context. To be able to do this,
> store a pointer to the description array in the state structure. This
> will allow for the later introduced callers (stage_2 ptdump) to specify
> their own page table description format to the ptdump parser.
> 
> Signed-off-by: Sebastian Ene <sebastianene@google.com>
> ---
>  arch/arm64/include/asm/ptdump.h |  1 +
>  arch/arm64/mm/ptdump.c          | 13 ++++++++-----
>  2 files changed, 9 insertions(+), 5 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

Will


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables
  2024-09-09 12:47 ` [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables Sebastian Ene
@ 2024-09-10 10:05   ` Will Deacon
  0 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2024-09-10 10:05 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, maz, oliver.upton, rananta,
	ryan.roberts, shahuang, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, linux-kernel, kernel-team

On Mon, Sep 09, 2024 at 12:47:20PM +0000, Sebastian Ene wrote:
> Ptdump uses the init_mm structure directly to dump the kernel
> pagetables. When ptdump is called on the stage-2 pagetables, this mm
> argument is not used. Prevent the level from being overwritten by
> checking the argument against NULL.
> 
> Signed-off-by: Sebastian Ene <sebastianene@google.com>
> ---
>  arch/arm64/mm/ptdump.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

Will


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality
  2024-09-10  9:57   ` Will Deacon
@ 2024-09-10 16:59     ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2024-09-10 16:59 UTC (permalink / raw)
  To: Will Deacon
  Cc: Sebastian Ene, akpm, alexghiti, ankita, ardb, catalin.marinas,
	christophe.leroy, james.morse, vdonnefort, mark.rutland,
	oliver.upton, rananta, ryan.roberts, shahuang, suzuki.poulose,
	yuzenghui, kvmarm, linux-arm-kernel, linux-kernel, kernel-team

On Tue, 10 Sep 2024 10:57:18 +0100,
Will Deacon <will@kernel.org> wrote:
> 
> On Mon, Sep 09, 2024 at 12:47:18PM +0000, Sebastian Ene wrote:
> > 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.
> > 
> > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > ---
> >  arch/arm64/include/asm/ptdump.h | 41 +++++++++++++++++++++++-
> >  arch/arm64/mm/ptdump.c          | 55 +++++++--------------------------
> >  2 files changed, 51 insertions(+), 45 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
> > index 5b1701c76d1c..bd5d3ee3e8dc 100644
> > --- a/arch/arm64/include/asm/ptdump.h
> > +++ b/arch/arm64/include/asm/ptdump.h
> > @@ -9,6 +9,7 @@
> >  
> >  #include <linux/mm_types.h>
> >  #include <linux/seq_file.h>
> > +#include <linux/ptdump.h>
> >  
> >  struct addr_marker {
> >  	unsigned long start_address;
> > @@ -21,14 +22,52 @@ struct ptdump_info {
> >  	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 note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
> > +	       u64 val);
> >  #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);
> >  #else
> >  static inline void ptdump_debugfs_register(struct ptdump_info *info,
> >  					   const char *name) { }
> > -#endif
> > +#endif /* CONFIG_PTDUMP_DEBUGFS */
> > +#else
> > +static inline void note_page(void *pt_st, unsigned long addr,
> > +			     int level, u64 val) { }
> 
> nit: but why isn't 'pt_st' a pointer to 'struct ptdump_state'?
> 
> Perhaps you should #include <linux/ptdump.h> before the #ifdef
> CONFIG_PTDUMP_CORE ?

Yup, that seems to do the trick. I'm folding this into the patch:

diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 71a7ed01153a4..6cf4aae052191 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -5,11 +5,12 @@
 #ifndef __ASM_PTDUMP_H
 #define __ASM_PTDUMP_H
 
+#include <linux/ptdump.h>
+
 #ifdef CONFIG_PTDUMP_CORE
 
 #include <linux/mm_types.h>
 #include <linux/seq_file.h>
-#include <linux/ptdump.h>
 
 struct addr_marker {
 	unsigned long start_address;
@@ -67,7 +68,7 @@ static inline void ptdump_debugfs_register(struct ptdump_info *info,
 					   const char *name) { }
 #endif /* CONFIG_PTDUMP_DEBUGFS */
 #else
-static inline void note_page(void *pt_st, unsigned long addr,
+static inline void note_page(struct ptdump_state *pt_st, unsigned long addr,
 			     int level, u64 val) { }
 #endif /* CONFIG_PTDUMP_CORE */
 
> In any case, the meat of the patch is fine:
> 
> Acked-by: Will Deacon <will@kernel.org>

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation
  2024-09-09 12:47 ` [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation Sebastian Ene
@ 2024-09-10 20:27   ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2024-09-10 20:27 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, oliver.upton, rananta,
	ryan.roberts, shahuang, suzuki.poulose, will, yuzenghui, kvmarm,
	linux-arm-kernel, linux-kernel, kernel-team

On Mon, 09 Sep 2024 13:47:21 +0100,
Sebastian Ene <sebastianene@google.com> wrote:
> 
> While arch/*/mem/ptdump handles the kernel pagetable dumping code,
> introduce KVM/ptdump to show the guest stage-2 pagetables. The
> separation is necessary because most of the definitions from the
> stage-2 pagetable reside in the KVM path and we will be invoking
> functionality specific to KVM. Introduce the PTDUMP_STAGE2_DEBUGFS config.
> 
> When a guest is created, register a new file entry under the guest
> debugfs dir which allows userspace to show the contents of the guest
> stage-2 pagetables when accessed.
> 
> Signed-off-by: Sebastian Ene <sebastianene@google.com>
> Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
> ---
>  arch/arm64/include/asm/kvm_host.h |   6 +
>  arch/arm64/kvm/Kconfig            |  17 ++
>  arch/arm64/kvm/Makefile           |   1 +
>  arch/arm64/kvm/arm.c              |   1 +
>  arch/arm64/kvm/ptdump.c           | 268 ++++++++++++++++++++++++++++++
>  5 files changed, 293 insertions(+)
>  create mode 100644 arch/arm64/kvm/ptdump.c
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index a33f5996ca9f..4acd589f086b 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -1473,4 +1473,10 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
>  		(pa + pi + pa3) == 1;					\
>  	})
>  
> +#ifdef CONFIG_PTDUMP_STAGE2_DEBUGFS
> +void kvm_s2_ptdump_create_debugfs(struct kvm *kvm);
> +#else
> +static inline void kvm_s2_ptdump_create_debugfs(struct kvm *kvm) {}
> +#endif /* CONFIG_PTDUMP_STAGE2_DEBUGFS */
> +

I made the executive decision to move this to kvm_mmu.h, as this is
slightly more logical.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables
  2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
                   ` (4 preceding siblings ...)
  2024-09-09 12:47 ` [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation Sebastian Ene
@ 2024-09-10 20:35 ` Marc Zyngier
  5 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2024-09-10 20:35 UTC (permalink / raw)
  To: akpm, alexghiti, ankita, ardb, catalin.marinas, christophe.leroy,
	james.morse, vdonnefort, mark.rutland, oliver.upton, rananta,
	ryan.roberts, shahuang, suzuki.poulose, will, yuzenghui,
	Sebastian Ene
  Cc: kvmarm, linux-arm-kernel, linux-kernel, kernel-team

On Mon, 09 Sep 2024 12:47:16 +0000, Sebastian Ene wrote:
> This series extends the ptdump support to allow dumping the guest
> stage-2 pagetables. When CONFIG_PTDUMP_STAGE2_DEBUGFS is enabled, ptdump
> registers the new following files under debugfs:
> - /sys/debug/kvm/<guest_id>/stage2_page_tables
> - /sys/debug/kvm/<guest_id>/stage2_levels
> - /sys/debug/kvm/<guest_id>/ipa_range
> 
> [...]

Applied to next, thanks!

[1/5] KVM: arm64: Move pagetable definitions to common header
      commit: 29caeda359da15d16963096043cda39530f81cc4
[2/5] arm64: ptdump: Expose the attribute parsing functionality
      commit: acc3d3a8176651a839056c7da4b925ea0bcc38c2
[3/5] arm64: ptdump: Use the ptdump description from a local context
      commit: 9182301a7bd2564fb050ade9820333c8b1adfcc2
[4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables
      commit: 79c4c7284f92d5e780c8532c343ca2cacfaf5125
[5/5] KVM: arm64: Register ptdump with debugfs on guest creation
      commit: 7c4f73548ed15476daf1101f66648085eda65067

Cheers,

	M.
-- 
Without deviation from the norm, progress is not possible.




^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-09-10 20:37 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-09 12:47 [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Sebastian Ene
2024-09-09 12:47 ` [PATCH v10 1/5] KVM: arm64: Move pagetable definitions to common header Sebastian Ene
2024-09-09 12:47 ` [PATCH v10 2/5] arm64: ptdump: Expose the attribute parsing functionality Sebastian Ene
2024-09-10  9:57   ` Will Deacon
2024-09-10 16:59     ` Marc Zyngier
2024-09-09 12:47 ` [PATCH v10 3/5] arm64: ptdump: Use the ptdump description from a local context Sebastian Ene
2024-09-10 10:03   ` Will Deacon
2024-09-09 12:47 ` [PATCH v10 4/5] arm64: ptdump: Don't override the level when operating on the stage-2 tables Sebastian Ene
2024-09-10 10:05   ` Will Deacon
2024-09-09 12:47 ` [PATCH v10 5/5] KVM: arm64: Register ptdump with debugfs on guest creation Sebastian Ene
2024-09-10 20:27   ` Marc Zyngier
2024-09-10 20:35 ` [PATCH v10 0/5] arm64: ptdump: View the second stage page-tables Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).