1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/seq_file.h>
3 #include <linux/debugfs.h>
4 #include <linux/sched.h>
6 #include <linux/kasan.h>
8 #include <asm/sections.h>
9 #include <asm/pgtable.h>
11 static unsigned long max_addr
;
14 unsigned long start_address
;
18 enum address_markers_idx
{
23 KASAN_SHADOW_START_NR
,
31 static struct addr_marker address_markers
[] = {
32 [IDENTITY_NR
] = {0, "Identity Mapping"},
33 [KERNEL_START_NR
] = {(unsigned long)_stext
, "Kernel Image Start"},
34 [KERNEL_END_NR
] = {(unsigned long)_end
, "Kernel Image End"},
36 [KASAN_SHADOW_START_NR
] = {KASAN_SHADOW_START
, "Kasan Shadow Start"},
37 [KASAN_SHADOW_END_NR
] = {KASAN_SHADOW_END
, "Kasan Shadow End"},
39 [VMEMMAP_NR
] = {0, "vmemmap Area"},
40 [VMALLOC_NR
] = {0, "vmalloc Area"},
41 [MODULES_NR
] = {0, "Modules Area"},
47 unsigned int current_prot
;
48 unsigned long start_address
;
49 unsigned long current_address
;
50 const struct addr_marker
*marker
;
53 static void print_prot(struct seq_file
*m
, unsigned int pr
, int level
)
55 static const char * const level_name
[] =
56 { "ASCE", "PGD", "PUD", "PMD", "PTE" };
58 seq_printf(m
, "%s ", level_name
[level
]);
59 if (pr
& _PAGE_INVALID
) {
63 seq_puts(m
, (pr
& _PAGE_PROTECT
) ? "RO " : "RW ");
64 seq_puts(m
, (pr
& _PAGE_NOEXEC
) ? "NX\n" : "X\n");
67 static void note_page(struct seq_file
*m
, struct pg_state
*st
,
68 unsigned int new_prot
, int level
)
70 static const char units
[] = "KMGTPE";
71 int width
= sizeof(unsigned long) * 2;
72 const char *unit
= units
;
73 unsigned int prot
, cur
;
77 * If we have a "break" in the series, we need to flush the state
78 * that we have now. "break" is either changing perms, levels or
79 * address space marker.
82 cur
= st
->current_prot
;
86 st
->current_prot
= new_prot
;
88 st
->marker
= address_markers
;
89 seq_printf(m
, "---[ %s ]---\n", st
->marker
->name
);
90 } else if (prot
!= cur
|| level
!= st
->level
||
91 st
->current_address
>= st
->marker
[1].start_address
) {
92 /* Print the actual finished series */
93 seq_printf(m
, "0x%0*lx-0x%0*lx ",
94 width
, st
->start_address
,
95 width
, st
->current_address
);
96 delta
= (st
->current_address
- st
->start_address
) >> 10;
97 while (!(delta
& 0x3ff) && unit
[1]) {
101 seq_printf(m
, "%9lu%c ", delta
, *unit
);
102 print_prot(m
, st
->current_prot
, st
->level
);
103 while (st
->current_address
>= st
->marker
[1].start_address
) {
105 seq_printf(m
, "---[ %s ]---\n", st
->marker
->name
);
107 st
->start_address
= st
->current_address
;
108 st
->current_prot
= new_prot
;
114 static void note_kasan_early_shadow_page(struct seq_file
*m
,
119 prot
= pte_val(*kasan_early_shadow_pte
) &
120 (_PAGE_PROTECT
| _PAGE_INVALID
| _PAGE_NOEXEC
);
121 note_page(m
, st
, prot
, 4);
126 * The actual page table walker functions. In order to keep the
127 * implementation of print_prot() short, we only check and pass
128 * _PAGE_INVALID and _PAGE_PROTECT flags to note_page() if a region,
129 * segment or page table entry is invalid or read-only.
130 * After all it's just a hint that the current level being walked
131 * contains an invalid or read-only entry.
133 static void walk_pte_level(struct seq_file
*m
, struct pg_state
*st
,
134 pmd_t
*pmd
, unsigned long addr
)
140 for (i
= 0; i
< PTRS_PER_PTE
&& addr
< max_addr
; i
++) {
141 st
->current_address
= addr
;
142 pte
= pte_offset_kernel(pmd
, addr
);
143 prot
= pte_val(*pte
) &
144 (_PAGE_PROTECT
| _PAGE_INVALID
| _PAGE_NOEXEC
);
145 note_page(m
, st
, prot
, 4);
150 static void walk_pmd_level(struct seq_file
*m
, struct pg_state
*st
,
151 pud_t
*pud
, unsigned long addr
)
158 if ((pud_val(*pud
) & PAGE_MASK
) == __pa(kasan_early_shadow_pmd
)) {
159 note_kasan_early_shadow_page(m
, st
);
164 pmd
= pmd_offset(pud
, addr
);
165 for (i
= 0; i
< PTRS_PER_PMD
&& addr
< max_addr
; i
++, pmd
++) {
166 st
->current_address
= addr
;
167 if (!pmd_none(*pmd
)) {
168 if (pmd_large(*pmd
)) {
169 prot
= pmd_val(*pmd
) &
170 (_SEGMENT_ENTRY_PROTECT
|
171 _SEGMENT_ENTRY_NOEXEC
);
172 note_page(m
, st
, prot
, 3);
174 walk_pte_level(m
, st
, pmd
, addr
);
176 note_page(m
, st
, _PAGE_INVALID
, 3);
181 static void walk_pud_level(struct seq_file
*m
, struct pg_state
*st
,
182 p4d_t
*p4d
, unsigned long addr
)
189 if ((p4d_val(*p4d
) & PAGE_MASK
) == __pa(kasan_early_shadow_pud
)) {
190 note_kasan_early_shadow_page(m
, st
);
195 pud
= pud_offset(p4d
, addr
);
196 for (i
= 0; i
< PTRS_PER_PUD
&& addr
< max_addr
; i
++, pud
++) {
197 st
->current_address
= addr
;
199 if (pud_large(*pud
)) {
200 prot
= pud_val(*pud
) &
201 (_REGION_ENTRY_PROTECT
|
202 _REGION_ENTRY_NOEXEC
);
203 note_page(m
, st
, prot
, 2);
205 walk_pmd_level(m
, st
, pud
, addr
);
207 note_page(m
, st
, _PAGE_INVALID
, 2);
212 static void walk_p4d_level(struct seq_file
*m
, struct pg_state
*st
,
213 pgd_t
*pgd
, unsigned long addr
)
219 if ((pgd_val(*pgd
) & PAGE_MASK
) == __pa(kasan_early_shadow_p4d
)) {
220 note_kasan_early_shadow_page(m
, st
);
225 p4d
= p4d_offset(pgd
, addr
);
226 for (i
= 0; i
< PTRS_PER_P4D
&& addr
< max_addr
; i
++, p4d
++) {
227 st
->current_address
= addr
;
229 walk_pud_level(m
, st
, p4d
, addr
);
231 note_page(m
, st
, _PAGE_INVALID
, 2);
236 static void walk_pgd_level(struct seq_file
*m
)
238 unsigned long addr
= 0;
243 memset(&st
, 0, sizeof(st
));
244 for (i
= 0; i
< PTRS_PER_PGD
&& addr
< max_addr
; i
++) {
245 st
.current_address
= addr
;
246 pgd
= pgd_offset_k(addr
);
248 walk_p4d_level(m
, &st
, pgd
, addr
);
250 note_page(m
, &st
, _PAGE_INVALID
, 1);
254 /* Flush out the last page */
255 st
.current_address
= max_addr
;
256 note_page(m
, &st
, 0, 0);
259 static int ptdump_show(struct seq_file
*m
, void *v
)
265 static int ptdump_open(struct inode
*inode
, struct file
*filp
)
267 return single_open(filp
, ptdump_show
, NULL
);
270 static const struct file_operations ptdump_fops
= {
274 .release
= single_release
,
277 static int pt_dump_init(void)
280 * Figure out the maximum virtual address being accessible with the
281 * kernel ASCE. We need this to keep the page table walker functions
282 * from accessing non-existent entries.
284 max_addr
= (S390_lowcore
.kernel_asce
& _REGION_ENTRY_TYPE_MASK
) >> 2;
285 max_addr
= 1UL << (max_addr
* 11 + 31);
286 address_markers
[MODULES_NR
].start_address
= MODULES_VADDR
;
287 address_markers
[VMEMMAP_NR
].start_address
= (unsigned long) vmemmap
;
288 address_markers
[VMALLOC_NR
].start_address
= VMALLOC_START
;
289 debugfs_create_file("kernel_page_tables", 0400, NULL
, NULL
, &ptdump_fops
);
292 device_initcall(pt_dump_init
);