33#include <linux/ptdump.h>
44#include <linux/seq_file.h>
55#include <linux/debugfs.h>
6+ #include <linux/sort.h>
67#include <linux/mm.h>
78#include <linux/kfence.h>
89#include <linux/kasan.h>
1516static unsigned long max_addr ;
1617
1718struct addr_marker {
19+ int is_start ;
1820 unsigned long start_address ;
1921 const char * name ;
2022};
2123
2224enum address_markers_idx {
23- IDENTITY_BEFORE_NR = 0 ,
24- IDENTITY_BEFORE_END_NR ,
25+ KVA_NR = 0 ,
26+ LOWCORE_START_NR ,
27+ LOWCORE_END_NR ,
2528 AMODE31_START_NR ,
2629 AMODE31_END_NR ,
2730 KERNEL_START_NR ,
@@ -30,8 +33,8 @@ enum address_markers_idx {
3033 KFENCE_START_NR ,
3134 KFENCE_END_NR ,
3235#endif
33- IDENTITY_AFTER_NR ,
34- IDENTITY_AFTER_END_NR ,
36+ IDENTITY_START_NR ,
37+ IDENTITY_END_NR ,
3538 VMEMMAP_NR ,
3639 VMEMMAP_END_NR ,
3740 VMALLOC_NR ,
@@ -59,43 +62,44 @@ enum address_markers_idx {
5962};
6063
6164static struct addr_marker address_markers [] = {
62- [IDENTITY_BEFORE_NR ] = {0 , "Identity Mapping Start" },
63- [IDENTITY_BEFORE_END_NR ] = {(unsigned long )_stext , "Identity Mapping End" },
64- [AMODE31_START_NR ] = {0 , "Amode31 Area Start" },
65- [AMODE31_END_NR ] = {0 , "Amode31 Area End" },
66- [KERNEL_START_NR ] = {(unsigned long )_stext , "Kernel Image Start" },
67- [KERNEL_END_NR ] = {(unsigned long )_end , "Kernel Image End" },
65+ [KVA_NR ] = {0 , 0 , "Kernel Virtual Address Space" },
66+ [LOWCORE_START_NR ] = {1 , 0 , "Lowcore Start" },
67+ [LOWCORE_END_NR ] = {0 , 0 , "Lowcore End" },
68+ [IDENTITY_START_NR ] = {1 , 0 , "Identity Mapping Start" },
69+ [IDENTITY_END_NR ] = {0 , 0 , "Identity Mapping End" },
70+ [AMODE31_START_NR ] = {1 , 0 , "Amode31 Area Start" },
71+ [AMODE31_END_NR ] = {0 , 0 , "Amode31 Area End" },
72+ [KERNEL_START_NR ] = {1 , (unsigned long )_stext , "Kernel Image Start" },
73+ [KERNEL_END_NR ] = {0 , (unsigned long )_end , "Kernel Image End" },
6874#ifdef CONFIG_KFENCE
69- [KFENCE_START_NR ] = {0 , "KFence Pool Start" },
70- [KFENCE_END_NR ] = {0 , "KFence Pool End" },
75+ [KFENCE_START_NR ] = {1 , 0 , "KFence Pool Start" },
76+ [KFENCE_END_NR ] = {0 , 0 , "KFence Pool End" },
7177#endif
72- [IDENTITY_AFTER_NR ] = {(unsigned long )_end , "Identity Mapping Start" },
73- [IDENTITY_AFTER_END_NR ] = {0 , "Identity Mapping End" },
74- [VMEMMAP_NR ] = {0 , "vmemmap Area Start" },
75- [VMEMMAP_END_NR ] = {0 , "vmemmap Area End" },
76- [VMALLOC_NR ] = {0 , "vmalloc Area Start" },
77- [VMALLOC_END_NR ] = {0 , "vmalloc Area End" },
78+ [VMEMMAP_NR ] = {1 , 0 , "vmemmap Area Start" },
79+ [VMEMMAP_END_NR ] = {0 , 0 , "vmemmap Area End" },
80+ [VMALLOC_NR ] = {1 , 0 , "vmalloc Area Start" },
81+ [VMALLOC_END_NR ] = {0 , 0 , "vmalloc Area End" },
7882#ifdef CONFIG_KMSAN
79- [KMSAN_VMALLOC_SHADOW_START_NR ] = {0 , "Kmsan vmalloc Shadow Start" },
80- [KMSAN_VMALLOC_SHADOW_END_NR ] = {0 , "Kmsan vmalloc Shadow End" },
81- [KMSAN_VMALLOC_ORIGIN_START_NR ] = {0 , "Kmsan vmalloc Origins Start" },
82- [KMSAN_VMALLOC_ORIGIN_END_NR ] = {0 , "Kmsan vmalloc Origins End" },
83- [KMSAN_MODULES_SHADOW_START_NR ] = {0 , "Kmsan Modules Shadow Start" },
84- [KMSAN_MODULES_SHADOW_END_NR ] = {0 , "Kmsan Modules Shadow End" },
85- [KMSAN_MODULES_ORIGIN_START_NR ] = {0 , "Kmsan Modules Origins Start" },
86- [KMSAN_MODULES_ORIGIN_END_NR ] = {0 , "Kmsan Modules Origins End" },
83+ [KMSAN_VMALLOC_SHADOW_START_NR ] = {1 , 0 , "Kmsan vmalloc Shadow Start" },
84+ [KMSAN_VMALLOC_SHADOW_END_NR ] = {0 , 0 , "Kmsan vmalloc Shadow End" },
85+ [KMSAN_VMALLOC_ORIGIN_START_NR ] = {1 , 0 , "Kmsan vmalloc Origins Start" },
86+ [KMSAN_VMALLOC_ORIGIN_END_NR ] = {0 , 0 , "Kmsan vmalloc Origins End" },
87+ [KMSAN_MODULES_SHADOW_START_NR ] = {1 , 0 , "Kmsan Modules Shadow Start" },
88+ [KMSAN_MODULES_SHADOW_END_NR ] = {0 , 0 , "Kmsan Modules Shadow End" },
89+ [KMSAN_MODULES_ORIGIN_START_NR ] = {1 , 0 , "Kmsan Modules Origins Start" },
90+ [KMSAN_MODULES_ORIGIN_END_NR ] = {0 , 0 , "Kmsan Modules Origins End" },
8791#endif
88- [MODULES_NR ] = {0 , "Modules Area Start" },
89- [MODULES_END_NR ] = {0 , "Modules Area End" },
90- [ABS_LOWCORE_NR ] = {0 , "Lowcore Area Start" },
91- [ABS_LOWCORE_END_NR ] = {0 , "Lowcore Area End" },
92- [MEMCPY_REAL_NR ] = {0 , "Real Memory Copy Area Start" },
93- [MEMCPY_REAL_END_NR ] = {0 , "Real Memory Copy Area End" },
92+ [MODULES_NR ] = {1 , 0 , "Modules Area Start" },
93+ [MODULES_END_NR ] = {0 , 0 , "Modules Area End" },
94+ [ABS_LOWCORE_NR ] = {1 , 0 , "Lowcore Area Start" },
95+ [ABS_LOWCORE_END_NR ] = {0 , 0 , "Lowcore Area End" },
96+ [MEMCPY_REAL_NR ] = {1 , 0 , "Real Memory Copy Area Start" },
97+ [MEMCPY_REAL_END_NR ] = {0 , 0 , "Real Memory Copy Area End" },
9498#ifdef CONFIG_KASAN
95- [KASAN_SHADOW_START_NR ] = {KASAN_SHADOW_START , "Kasan Shadow Start" },
96- [KASAN_SHADOW_END_NR ] = {KASAN_SHADOW_END , "Kasan Shadow End" },
99+ [KASAN_SHADOW_START_NR ] = {1 , KASAN_SHADOW_START , "Kasan Shadow Start" },
100+ [KASAN_SHADOW_END_NR ] = {0 , KASAN_SHADOW_END , "Kasan Shadow End" },
97101#endif
98- { -1 , NULL }
102+ {1 , -1UL , NULL }
99103};
100104
101105struct pg_state {
@@ -163,6 +167,19 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
163167 st -> wx_pages += (addr - st -> start_address ) / PAGE_SIZE ;
164168}
165169
170+ static void note_page_update_state (struct pg_state * st , unsigned long addr , unsigned int prot , int level )
171+ {
172+ struct seq_file * m = st -> seq ;
173+
174+ while (addr >= st -> marker [1 ].start_address ) {
175+ st -> marker ++ ;
176+ pt_dump_seq_printf (m , "---[ %s ]---\n" , st -> marker -> name );
177+ }
178+ st -> start_address = addr ;
179+ st -> current_prot = prot ;
180+ st -> level = level ;
181+ }
182+
166183static void note_page (struct ptdump_state * pt_st , unsigned long addr , int level , u64 val )
167184{
168185 int width = sizeof (unsigned long ) * 2 ;
@@ -186,9 +203,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
186203 addr = max_addr ;
187204 if (st -> level == -1 ) {
188205 pt_dump_seq_printf (m , "---[ %s ]---\n" , st -> marker -> name );
189- st -> start_address = addr ;
190- st -> current_prot = prot ;
191- st -> level = level ;
206+ note_page_update_state (st , addr , prot , level );
192207 } else if (prot != st -> current_prot || level != st -> level ||
193208 addr >= st -> marker [1 ].start_address ) {
194209 note_prot_wx (st , addr );
@@ -202,13 +217,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
202217 }
203218 pt_dump_seq_printf (m , "%9lu%c " , delta , * unit );
204219 print_prot (m , st -> current_prot , st -> level );
205- while (addr >= st -> marker [1 ].start_address ) {
206- st -> marker ++ ;
207- pt_dump_seq_printf (m , "---[ %s ]---\n" , st -> marker -> name );
208- }
209- st -> start_address = addr ;
210- st -> current_prot = prot ;
211- st -> level = level ;
220+ note_page_update_state (st , addr , prot , level );
212221 }
213222}
214223
@@ -280,37 +289,45 @@ static int ptdump_show(struct seq_file *m, void *v)
280289DEFINE_SHOW_ATTRIBUTE (ptdump );
281290#endif /* CONFIG_PTDUMP_DEBUGFS */
282291
283- /*
284- * Heapsort from lib/sort.c is not a stable sorting algorithm, do a simple
285- * insertion sort to preserve the original order of markers with the same
286- * start address.
287- */
288- static void sort_address_markers (void )
292+ static int ptdump_cmp (const void * a , const void * b )
289293{
290- struct addr_marker tmp ;
291- int i , j ;
294+ const struct addr_marker * ama = a ;
295+ const struct addr_marker * amb = b ;
292296
293- for (i = 1 ; i < ARRAY_SIZE (address_markers ) - 1 ; i ++ ) {
294- tmp = address_markers [i ];
295- for (j = i - 1 ; j >= 0 && address_markers [j ].start_address > tmp .start_address ; j -- )
296- address_markers [j + 1 ] = address_markers [j ];
297- address_markers [j + 1 ] = tmp ;
298- }
297+ if (ama -> start_address > amb -> start_address )
298+ return 1 ;
299+ if (ama -> start_address < amb -> start_address )
300+ return -1 ;
301+ /*
302+ * If the start addresses of two markers are identical consider the
303+ * marker which defines the start of an area higher than the one which
304+ * defines the end of an area. This keeps pairs of markers sorted.
305+ */
306+ if (ama -> is_start )
307+ return 1 ;
308+ if (amb -> is_start )
309+ return -1 ;
310+ return 0 ;
299311}
300312
301313static int pt_dump_init (void )
302314{
303315#ifdef CONFIG_KFENCE
304316 unsigned long kfence_start = (unsigned long )__kfence_pool ;
305317#endif
318+ unsigned long lowcore = (unsigned long )get_lowcore ();
319+
306320 /*
307321 * Figure out the maximum virtual address being accessible with the
308322 * kernel ASCE. We need this to keep the page table walker functions
309323 * from accessing non-existent entries.
310324 */
311325 max_addr = (get_lowcore ()-> kernel_asce .val & _REGION_ENTRY_TYPE_MASK ) >> 2 ;
312326 max_addr = 1UL << (max_addr * 11 + 31 );
313- address_markers [IDENTITY_AFTER_END_NR ].start_address = ident_map_size ;
327+ address_markers [LOWCORE_START_NR ].start_address = lowcore ;
328+ address_markers [LOWCORE_END_NR ].start_address = lowcore + sizeof (struct lowcore );
329+ address_markers [IDENTITY_START_NR ].start_address = __identity_base ;
330+ address_markers [IDENTITY_END_NR ].start_address = __identity_base + ident_map_size ;
314331 address_markers [AMODE31_START_NR ].start_address = (unsigned long )__samode31 ;
315332 address_markers [AMODE31_END_NR ].start_address = (unsigned long )__eamode31 ;
316333 address_markers [MODULES_NR ].start_address = MODULES_VADDR ;
@@ -337,7 +354,8 @@ static int pt_dump_init(void)
337354 address_markers [KMSAN_MODULES_ORIGIN_START_NR ].start_address = KMSAN_MODULES_ORIGIN_START ;
338355 address_markers [KMSAN_MODULES_ORIGIN_END_NR ].start_address = KMSAN_MODULES_ORIGIN_END ;
339356#endif
340- sort_address_markers ();
357+ sort (address_markers , ARRAY_SIZE (address_markers ) - 1 ,
358+ sizeof (address_markers [0 ]), ptdump_cmp , NULL );
341359#ifdef CONFIG_PTDUMP_DEBUGFS
342360 debugfs_create_file ("kernel_page_tables" , 0400 , NULL , NULL , & ptdump_fops );
343361#endif /* CONFIG_PTDUMP_DEBUGFS */
0 commit comments