3
3
#include <linux/ptdump.h>
4
4
#include <linux/seq_file.h>
5
5
#include <linux/debugfs.h>
6
+ #include <linux/sort.h>
6
7
#include <linux/mm.h>
7
8
#include <linux/kfence.h>
8
9
#include <linux/kasan.h>
15
16
static unsigned long max_addr ;
16
17
17
18
struct addr_marker {
19
+ int is_start ;
18
20
unsigned long start_address ;
19
21
const char * name ;
20
22
};
21
23
22
24
enum 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 ,
25
28
AMODE31_START_NR ,
26
29
AMODE31_END_NR ,
27
30
KERNEL_START_NR ,
@@ -30,8 +33,8 @@ enum address_markers_idx {
30
33
KFENCE_START_NR ,
31
34
KFENCE_END_NR ,
32
35
#endif
33
- IDENTITY_AFTER_NR ,
34
- IDENTITY_AFTER_END_NR ,
36
+ IDENTITY_START_NR ,
37
+ IDENTITY_END_NR ,
35
38
VMEMMAP_NR ,
36
39
VMEMMAP_END_NR ,
37
40
VMALLOC_NR ,
@@ -59,43 +62,44 @@ enum address_markers_idx {
59
62
};
60
63
61
64
static 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" },
68
74
#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" },
71
77
#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" },
78
82
#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" },
87
91
#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" },
94
98
#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" },
97
101
#endif
98
- { -1 , NULL }
102
+ {1 , -1UL , NULL }
99
103
};
100
104
101
105
struct pg_state {
@@ -163,6 +167,19 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
163
167
st -> wx_pages += (addr - st -> start_address ) / PAGE_SIZE ;
164
168
}
165
169
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
+
166
183
static void note_page (struct ptdump_state * pt_st , unsigned long addr , int level , u64 val )
167
184
{
168
185
int width = sizeof (unsigned long ) * 2 ;
@@ -186,9 +203,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
186
203
addr = max_addr ;
187
204
if (st -> level == -1 ) {
188
205
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 );
192
207
} else if (prot != st -> current_prot || level != st -> level ||
193
208
addr >= st -> marker [1 ].start_address ) {
194
209
note_prot_wx (st , addr );
@@ -202,13 +217,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
202
217
}
203
218
pt_dump_seq_printf (m , "%9lu%c " , delta , * unit );
204
219
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 );
212
221
}
213
222
}
214
223
@@ -280,37 +289,45 @@ static int ptdump_show(struct seq_file *m, void *v)
280
289
DEFINE_SHOW_ATTRIBUTE (ptdump );
281
290
#endif /* CONFIG_PTDUMP_DEBUGFS */
282
291
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 )
289
293
{
290
- struct addr_marker tmp ;
291
- int i , j ;
294
+ const struct addr_marker * ama = a ;
295
+ const struct addr_marker * amb = b ;
292
296
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 ;
299
311
}
300
312
301
313
static int pt_dump_init (void )
302
314
{
303
315
#ifdef CONFIG_KFENCE
304
316
unsigned long kfence_start = (unsigned long )__kfence_pool ;
305
317
#endif
318
+ unsigned long lowcore = (unsigned long )get_lowcore ();
319
+
306
320
/*
307
321
* Figure out the maximum virtual address being accessible with the
308
322
* kernel ASCE. We need this to keep the page table walker functions
309
323
* from accessing non-existent entries.
310
324
*/
311
325
max_addr = (get_lowcore ()-> kernel_asce .val & _REGION_ENTRY_TYPE_MASK ) >> 2 ;
312
326
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 ;
314
331
address_markers [AMODE31_START_NR ].start_address = (unsigned long )__samode31 ;
315
332
address_markers [AMODE31_END_NR ].start_address = (unsigned long )__eamode31 ;
316
333
address_markers [MODULES_NR ].start_address = MODULES_VADDR ;
@@ -337,7 +354,8 @@ static int pt_dump_init(void)
337
354
address_markers [KMSAN_MODULES_ORIGIN_START_NR ].start_address = KMSAN_MODULES_ORIGIN_START ;
338
355
address_markers [KMSAN_MODULES_ORIGIN_END_NR ].start_address = KMSAN_MODULES_ORIGIN_END ;
339
356
#endif
340
- sort_address_markers ();
357
+ sort (address_markers , ARRAY_SIZE (address_markers ) - 1 ,
358
+ sizeof (address_markers [0 ]), ptdump_cmp , NULL );
341
359
#ifdef CONFIG_PTDUMP_DEBUGFS
342
360
debugfs_create_file ("kernel_page_tables" , 0400 , NULL , NULL , & ptdump_fops );
343
361
#endif /* CONFIG_PTDUMP_DEBUGFS */
0 commit comments