1c048ddf8SAnshuman Khandual // SPDX-License-Identifier: GPL-2.0-only 2c048ddf8SAnshuman Khandual /* 3c048ddf8SAnshuman Khandual * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4c048ddf8SAnshuman Khandual * Debug helper to dump the current kernel pagetables of the system 5c048ddf8SAnshuman Khandual * so that we can see what the various memory ranges are set to. 6c048ddf8SAnshuman Khandual * 7c048ddf8SAnshuman Khandual * Derived from x86 and arm implementation: 8c048ddf8SAnshuman Khandual * (C) Copyright 2008 Intel Corporation 9c048ddf8SAnshuman Khandual * 10c048ddf8SAnshuman Khandual * Author: Arjan van de Ven <arjan@linux.intel.com> 11c048ddf8SAnshuman Khandual */ 12c048ddf8SAnshuman Khandual #include <linux/debugfs.h> 13c048ddf8SAnshuman Khandual #include <linux/errno.h> 14c048ddf8SAnshuman Khandual #include <linux/fs.h> 15c048ddf8SAnshuman Khandual #include <linux/io.h> 16c048ddf8SAnshuman Khandual #include <linux/init.h> 17c048ddf8SAnshuman Khandual #include <linux/mm.h> 18c048ddf8SAnshuman Khandual #include <linux/ptdump.h> 19c048ddf8SAnshuman Khandual #include <linux/sched.h> 20c048ddf8SAnshuman Khandual #include <linux/seq_file.h> 21c048ddf8SAnshuman Khandual 22c048ddf8SAnshuman Khandual #include <asm/fixmap.h> 23c048ddf8SAnshuman Khandual #include <asm/kasan.h> 24c048ddf8SAnshuman Khandual #include <asm/memory.h> 25c048ddf8SAnshuman Khandual #include <asm/pgtable-hwdef.h> 26c048ddf8SAnshuman Khandual #include <asm/ptdump.h> 27c048ddf8SAnshuman Khandual 28c048ddf8SAnshuman Khandual 29c048ddf8SAnshuman Khandual enum address_markers_idx { 30c048ddf8SAnshuman Khandual PAGE_OFFSET_NR = 0, 31c048ddf8SAnshuman Khandual PAGE_END_NR, 320fea6e9aSAndrey Konovalov #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) 33c048ddf8SAnshuman Khandual KASAN_START_NR, 34c048ddf8SAnshuman Khandual #endif 35c048ddf8SAnshuman Khandual }; 36c048ddf8SAnshuman Khandual 37c048ddf8SAnshuman Khandual static struct addr_marker address_markers[] = { 38c048ddf8SAnshuman Khandual { PAGE_OFFSET, "Linear Mapping start" }, 39c048ddf8SAnshuman Khandual { 0 /* PAGE_END */, "Linear Mapping end" }, 400fea6e9aSAndrey Konovalov #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) 41c048ddf8SAnshuman Khandual { 0 /* KASAN_SHADOW_START */, "Kasan shadow start" }, 42c048ddf8SAnshuman Khandual { KASAN_SHADOW_END, "Kasan shadow end" }, 43c048ddf8SAnshuman Khandual #endif 44c048ddf8SAnshuman Khandual { BPF_JIT_REGION_START, "BPF start" }, 45c048ddf8SAnshuman Khandual { BPF_JIT_REGION_END, "BPF end" }, 46c048ddf8SAnshuman Khandual { MODULES_VADDR, "Modules start" }, 47c048ddf8SAnshuman Khandual { MODULES_END, "Modules end" }, 48c048ddf8SAnshuman Khandual { VMALLOC_START, "vmalloc() area" }, 49c048ddf8SAnshuman Khandual { VMALLOC_END, "vmalloc() end" }, 50c048ddf8SAnshuman Khandual { FIXADDR_START, "Fixmap start" }, 51c048ddf8SAnshuman Khandual { FIXADDR_TOP, "Fixmap end" }, 52c048ddf8SAnshuman Khandual { PCI_IO_START, "PCI I/O start" }, 53c048ddf8SAnshuman Khandual { PCI_IO_END, "PCI I/O end" }, 54c048ddf8SAnshuman Khandual #ifdef CONFIG_SPARSEMEM_VMEMMAP 55c048ddf8SAnshuman Khandual { VMEMMAP_START, "vmemmap start" }, 56c048ddf8SAnshuman Khandual { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" }, 57c048ddf8SAnshuman Khandual #endif 58c048ddf8SAnshuman Khandual { -1, NULL }, 59c048ddf8SAnshuman Khandual }; 60c048ddf8SAnshuman Khandual 61c048ddf8SAnshuman Khandual #define pt_dump_seq_printf(m, fmt, args...) \ 62c048ddf8SAnshuman Khandual ({ \ 63c048ddf8SAnshuman Khandual if (m) \ 64c048ddf8SAnshuman Khandual seq_printf(m, fmt, ##args); \ 65c048ddf8SAnshuman Khandual }) 66c048ddf8SAnshuman Khandual 67c048ddf8SAnshuman Khandual #define pt_dump_seq_puts(m, fmt) \ 68c048ddf8SAnshuman Khandual ({ \ 69c048ddf8SAnshuman Khandual if (m) \ 70c048ddf8SAnshuman Khandual seq_printf(m, fmt); \ 71c048ddf8SAnshuman Khandual }) 72c048ddf8SAnshuman Khandual 73c048ddf8SAnshuman Khandual /* 74c048ddf8SAnshuman Khandual * The page dumper groups page table entries of the same type into a single 75c048ddf8SAnshuman Khandual * description. It uses pg_state to track the range information while 76c048ddf8SAnshuman Khandual * iterating over the pte entries. When the continuity is broken it then 77c048ddf8SAnshuman Khandual * dumps out a description of the range. 78c048ddf8SAnshuman Khandual */ 79c048ddf8SAnshuman Khandual struct pg_state { 80c048ddf8SAnshuman Khandual struct ptdump_state ptdump; 81c048ddf8SAnshuman Khandual struct seq_file *seq; 82c048ddf8SAnshuman Khandual const struct addr_marker *marker; 83c048ddf8SAnshuman Khandual unsigned long start_address; 84c048ddf8SAnshuman Khandual int level; 85c048ddf8SAnshuman Khandual u64 current_prot; 86c048ddf8SAnshuman Khandual bool check_wx; 87c048ddf8SAnshuman Khandual unsigned long wx_pages; 88c048ddf8SAnshuman Khandual unsigned long uxn_pages; 89c048ddf8SAnshuman Khandual }; 90c048ddf8SAnshuman Khandual 91c048ddf8SAnshuman Khandual struct prot_bits { 92c048ddf8SAnshuman Khandual u64 mask; 93c048ddf8SAnshuman Khandual u64 val; 94c048ddf8SAnshuman Khandual const char *set; 95c048ddf8SAnshuman Khandual const char *clear; 96c048ddf8SAnshuman Khandual }; 97c048ddf8SAnshuman Khandual 98c048ddf8SAnshuman Khandual static const struct prot_bits pte_bits[] = { 99c048ddf8SAnshuman Khandual { 100c048ddf8SAnshuman Khandual .mask = PTE_VALID, 101c048ddf8SAnshuman Khandual .val = PTE_VALID, 102c048ddf8SAnshuman Khandual .set = " ", 103c048ddf8SAnshuman Khandual .clear = "F", 104c048ddf8SAnshuman Khandual }, { 105c048ddf8SAnshuman Khandual .mask = PTE_USER, 106c048ddf8SAnshuman Khandual .val = PTE_USER, 107c048ddf8SAnshuman Khandual .set = "USR", 108c048ddf8SAnshuman Khandual .clear = " ", 109c048ddf8SAnshuman Khandual }, { 110c048ddf8SAnshuman Khandual .mask = PTE_RDONLY, 111c048ddf8SAnshuman Khandual .val = PTE_RDONLY, 112c048ddf8SAnshuman Khandual .set = "ro", 113c048ddf8SAnshuman Khandual .clear = "RW", 114c048ddf8SAnshuman Khandual }, { 115c048ddf8SAnshuman Khandual .mask = PTE_PXN, 116c048ddf8SAnshuman Khandual .val = PTE_PXN, 117c048ddf8SAnshuman Khandual .set = "NX", 118c048ddf8SAnshuman Khandual .clear = "x ", 119c048ddf8SAnshuman Khandual }, { 120c048ddf8SAnshuman Khandual .mask = PTE_SHARED, 121c048ddf8SAnshuman Khandual .val = PTE_SHARED, 122c048ddf8SAnshuman Khandual .set = "SHD", 123c048ddf8SAnshuman Khandual .clear = " ", 124c048ddf8SAnshuman Khandual }, { 125c048ddf8SAnshuman Khandual .mask = PTE_AF, 126c048ddf8SAnshuman Khandual .val = PTE_AF, 127c048ddf8SAnshuman Khandual .set = "AF", 128c048ddf8SAnshuman Khandual .clear = " ", 129c048ddf8SAnshuman Khandual }, { 130c048ddf8SAnshuman Khandual .mask = PTE_NG, 131c048ddf8SAnshuman Khandual .val = PTE_NG, 132c048ddf8SAnshuman Khandual .set = "NG", 133c048ddf8SAnshuman Khandual .clear = " ", 134c048ddf8SAnshuman Khandual }, { 135c048ddf8SAnshuman Khandual .mask = PTE_CONT, 136c048ddf8SAnshuman Khandual .val = PTE_CONT, 137c048ddf8SAnshuman Khandual .set = "CON", 138c048ddf8SAnshuman Khandual .clear = " ", 139c048ddf8SAnshuman Khandual }, { 140c048ddf8SAnshuman Khandual .mask = PTE_TABLE_BIT, 141c048ddf8SAnshuman Khandual .val = PTE_TABLE_BIT, 142c048ddf8SAnshuman Khandual .set = " ", 143c048ddf8SAnshuman Khandual .clear = "BLK", 144c048ddf8SAnshuman Khandual }, { 145c048ddf8SAnshuman Khandual .mask = PTE_UXN, 146c048ddf8SAnshuman Khandual .val = PTE_UXN, 147c048ddf8SAnshuman Khandual .set = "UXN", 148c048ddf8SAnshuman Khandual .clear = " ", 149c048ddf8SAnshuman Khandual }, { 150c048ddf8SAnshuman Khandual .mask = PTE_GP, 151c048ddf8SAnshuman Khandual .val = PTE_GP, 152c048ddf8SAnshuman Khandual .set = "GP", 153c048ddf8SAnshuman Khandual .clear = " ", 154c048ddf8SAnshuman Khandual }, { 155c048ddf8SAnshuman Khandual .mask = PTE_ATTRINDX_MASK, 156c048ddf8SAnshuman Khandual .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE), 157c048ddf8SAnshuman Khandual .set = "DEVICE/nGnRnE", 158c048ddf8SAnshuman Khandual }, { 159c048ddf8SAnshuman Khandual .mask = PTE_ATTRINDX_MASK, 160c048ddf8SAnshuman Khandual .val = PTE_ATTRINDX(MT_DEVICE_nGnRE), 161c048ddf8SAnshuman Khandual .set = "DEVICE/nGnRE", 162c048ddf8SAnshuman Khandual }, { 163c048ddf8SAnshuman Khandual .mask = PTE_ATTRINDX_MASK, 164c048ddf8SAnshuman Khandual .val = PTE_ATTRINDX(MT_DEVICE_GRE), 165c048ddf8SAnshuman Khandual .set = "DEVICE/GRE", 166c048ddf8SAnshuman Khandual }, { 167c048ddf8SAnshuman Khandual .mask = PTE_ATTRINDX_MASK, 168c048ddf8SAnshuman Khandual .val = PTE_ATTRINDX(MT_NORMAL_NC), 169c048ddf8SAnshuman Khandual .set = "MEM/NORMAL-NC", 170c048ddf8SAnshuman Khandual }, { 171c048ddf8SAnshuman Khandual .mask = PTE_ATTRINDX_MASK, 172c048ddf8SAnshuman Khandual .val = PTE_ATTRINDX(MT_NORMAL), 173c048ddf8SAnshuman Khandual .set = "MEM/NORMAL", 174baab8532SWill Deacon }, { 175baab8532SWill Deacon .mask = PTE_ATTRINDX_MASK, 176baab8532SWill Deacon .val = PTE_ATTRINDX(MT_NORMAL_TAGGED), 177baab8532SWill Deacon .set = "MEM/NORMAL-TAGGED", 178c048ddf8SAnshuman Khandual } 179c048ddf8SAnshuman Khandual }; 180c048ddf8SAnshuman Khandual 181c048ddf8SAnshuman Khandual struct pg_level { 182c048ddf8SAnshuman Khandual const struct prot_bits *bits; 183c048ddf8SAnshuman Khandual const char *name; 184c048ddf8SAnshuman Khandual size_t num; 185c048ddf8SAnshuman Khandual u64 mask; 186c048ddf8SAnshuman Khandual }; 187c048ddf8SAnshuman Khandual 188c048ddf8SAnshuman Khandual static struct pg_level pg_level[] = { 189c048ddf8SAnshuman Khandual { /* pgd */ 190c048ddf8SAnshuman Khandual .name = "PGD", 191c048ddf8SAnshuman Khandual .bits = pte_bits, 192c048ddf8SAnshuman Khandual .num = ARRAY_SIZE(pte_bits), 193c048ddf8SAnshuman Khandual }, { /* p4d */ 194c048ddf8SAnshuman Khandual .name = "P4D", 195c048ddf8SAnshuman Khandual .bits = pte_bits, 196c048ddf8SAnshuman Khandual .num = ARRAY_SIZE(pte_bits), 197c048ddf8SAnshuman Khandual }, { /* pud */ 198c048ddf8SAnshuman Khandual .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD", 199c048ddf8SAnshuman Khandual .bits = pte_bits, 200c048ddf8SAnshuman Khandual .num = ARRAY_SIZE(pte_bits), 201c048ddf8SAnshuman Khandual }, { /* pmd */ 202c048ddf8SAnshuman Khandual .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD", 203c048ddf8SAnshuman Khandual .bits = pte_bits, 204c048ddf8SAnshuman Khandual .num = ARRAY_SIZE(pte_bits), 205c048ddf8SAnshuman Khandual }, { /* pte */ 206c048ddf8SAnshuman Khandual .name = "PTE", 207c048ddf8SAnshuman Khandual .bits = pte_bits, 208c048ddf8SAnshuman Khandual .num = ARRAY_SIZE(pte_bits), 209c048ddf8SAnshuman Khandual }, 210c048ddf8SAnshuman Khandual }; 211c048ddf8SAnshuman Khandual 212c048ddf8SAnshuman Khandual static void dump_prot(struct pg_state *st, const struct prot_bits *bits, 213c048ddf8SAnshuman Khandual size_t num) 214c048ddf8SAnshuman Khandual { 215c048ddf8SAnshuman Khandual unsigned i; 216c048ddf8SAnshuman Khandual 217c048ddf8SAnshuman Khandual for (i = 0; i < num; i++, bits++) { 218c048ddf8SAnshuman Khandual const char *s; 219c048ddf8SAnshuman Khandual 220c048ddf8SAnshuman Khandual if ((st->current_prot & bits->mask) == bits->val) 221c048ddf8SAnshuman Khandual s = bits->set; 222c048ddf8SAnshuman Khandual else 223c048ddf8SAnshuman Khandual s = bits->clear; 224c048ddf8SAnshuman Khandual 225c048ddf8SAnshuman Khandual if (s) 226c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, " %s", s); 227c048ddf8SAnshuman Khandual } 228c048ddf8SAnshuman Khandual } 229c048ddf8SAnshuman Khandual 230c048ddf8SAnshuman Khandual static void note_prot_uxn(struct pg_state *st, unsigned long addr) 231c048ddf8SAnshuman Khandual { 232c048ddf8SAnshuman Khandual if (!st->check_wx) 233c048ddf8SAnshuman Khandual return; 234c048ddf8SAnshuman Khandual 235c048ddf8SAnshuman Khandual if ((st->current_prot & PTE_UXN) == PTE_UXN) 236c048ddf8SAnshuman Khandual return; 237c048ddf8SAnshuman Khandual 238c048ddf8SAnshuman Khandual WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n", 239c048ddf8SAnshuman Khandual (void *)st->start_address, (void *)st->start_address); 240c048ddf8SAnshuman Khandual 241c048ddf8SAnshuman Khandual st->uxn_pages += (addr - st->start_address) / PAGE_SIZE; 242c048ddf8SAnshuman Khandual } 243c048ddf8SAnshuman Khandual 244c048ddf8SAnshuman Khandual static void note_prot_wx(struct pg_state *st, unsigned long addr) 245c048ddf8SAnshuman Khandual { 246c048ddf8SAnshuman Khandual if (!st->check_wx) 247c048ddf8SAnshuman Khandual return; 248c048ddf8SAnshuman Khandual if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY) 249c048ddf8SAnshuman Khandual return; 250c048ddf8SAnshuman Khandual if ((st->current_prot & PTE_PXN) == PTE_PXN) 251c048ddf8SAnshuman Khandual return; 252c048ddf8SAnshuman Khandual 253c048ddf8SAnshuman Khandual WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n", 254c048ddf8SAnshuman Khandual (void *)st->start_address, (void *)st->start_address); 255c048ddf8SAnshuman Khandual 256c048ddf8SAnshuman Khandual st->wx_pages += (addr - st->start_address) / PAGE_SIZE; 257c048ddf8SAnshuman Khandual } 258c048ddf8SAnshuman Khandual 259c048ddf8SAnshuman Khandual static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, 260c048ddf8SAnshuman Khandual u64 val) 261c048ddf8SAnshuman Khandual { 262c048ddf8SAnshuman Khandual struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); 263c048ddf8SAnshuman Khandual static const char units[] = "KMGTPE"; 264c048ddf8SAnshuman Khandual u64 prot = 0; 265c048ddf8SAnshuman Khandual 266c048ddf8SAnshuman Khandual if (level >= 0) 267c048ddf8SAnshuman Khandual prot = val & pg_level[level].mask; 268c048ddf8SAnshuman Khandual 269c048ddf8SAnshuman Khandual if (st->level == -1) { 270c048ddf8SAnshuman Khandual st->level = level; 271c048ddf8SAnshuman Khandual st->current_prot = prot; 272c048ddf8SAnshuman Khandual st->start_address = addr; 273c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 274c048ddf8SAnshuman Khandual } else if (prot != st->current_prot || level != st->level || 275c048ddf8SAnshuman Khandual addr >= st->marker[1].start_address) { 276c048ddf8SAnshuman Khandual const char *unit = units; 277c048ddf8SAnshuman Khandual unsigned long delta; 278c048ddf8SAnshuman Khandual 279c048ddf8SAnshuman Khandual if (st->current_prot) { 280c048ddf8SAnshuman Khandual note_prot_uxn(st, addr); 281c048ddf8SAnshuman Khandual note_prot_wx(st, addr); 282c048ddf8SAnshuman Khandual } 283c048ddf8SAnshuman Khandual 284c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ", 285c048ddf8SAnshuman Khandual st->start_address, addr); 286c048ddf8SAnshuman Khandual 287c048ddf8SAnshuman Khandual delta = (addr - st->start_address) >> 10; 288c048ddf8SAnshuman Khandual while (!(delta & 1023) && unit[1]) { 289c048ddf8SAnshuman Khandual delta >>= 10; 290c048ddf8SAnshuman Khandual unit++; 291c048ddf8SAnshuman Khandual } 292c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit, 293c048ddf8SAnshuman Khandual pg_level[st->level].name); 294c048ddf8SAnshuman Khandual if (st->current_prot && pg_level[st->level].bits) 295c048ddf8SAnshuman Khandual dump_prot(st, pg_level[st->level].bits, 296c048ddf8SAnshuman Khandual pg_level[st->level].num); 297c048ddf8SAnshuman Khandual pt_dump_seq_puts(st->seq, "\n"); 298c048ddf8SAnshuman Khandual 299c048ddf8SAnshuman Khandual if (addr >= st->marker[1].start_address) { 300c048ddf8SAnshuman Khandual st->marker++; 301c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 302c048ddf8SAnshuman Khandual } 303c048ddf8SAnshuman Khandual 304c048ddf8SAnshuman Khandual st->start_address = addr; 305c048ddf8SAnshuman Khandual st->current_prot = prot; 306c048ddf8SAnshuman Khandual st->level = level; 307c048ddf8SAnshuman Khandual } 308c048ddf8SAnshuman Khandual 309c048ddf8SAnshuman Khandual if (addr >= st->marker[1].start_address) { 310c048ddf8SAnshuman Khandual st->marker++; 311c048ddf8SAnshuman Khandual pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 312c048ddf8SAnshuman Khandual } 313c048ddf8SAnshuman Khandual 314c048ddf8SAnshuman Khandual } 315c048ddf8SAnshuman Khandual 316c048ddf8SAnshuman Khandual void ptdump_walk(struct seq_file *s, struct ptdump_info *info) 317c048ddf8SAnshuman Khandual { 318c048ddf8SAnshuman Khandual unsigned long end = ~0UL; 319c048ddf8SAnshuman Khandual struct pg_state st; 320c048ddf8SAnshuman Khandual 321c048ddf8SAnshuman Khandual if (info->base_addr < TASK_SIZE_64) 322c048ddf8SAnshuman Khandual end = TASK_SIZE_64; 323c048ddf8SAnshuman Khandual 324c048ddf8SAnshuman Khandual st = (struct pg_state){ 325c048ddf8SAnshuman Khandual .seq = s, 326c048ddf8SAnshuman Khandual .marker = info->markers, 327*b9ba6809SHailong Liu .level = -1, 328c048ddf8SAnshuman Khandual .ptdump = { 329c048ddf8SAnshuman Khandual .note_page = note_page, 330c048ddf8SAnshuman Khandual .range = (struct ptdump_range[]){ 331c048ddf8SAnshuman Khandual {info->base_addr, end}, 332c048ddf8SAnshuman Khandual {0, 0} 333c048ddf8SAnshuman Khandual } 334c048ddf8SAnshuman Khandual } 335c048ddf8SAnshuman Khandual }; 336c048ddf8SAnshuman Khandual 337c048ddf8SAnshuman Khandual ptdump_walk_pgd(&st.ptdump, info->mm, NULL); 338c048ddf8SAnshuman Khandual } 339c048ddf8SAnshuman Khandual 340c048ddf8SAnshuman Khandual static void ptdump_initialize(void) 341c048ddf8SAnshuman Khandual { 342c048ddf8SAnshuman Khandual unsigned i, j; 343c048ddf8SAnshuman Khandual 344c048ddf8SAnshuman Khandual for (i = 0; i < ARRAY_SIZE(pg_level); i++) 345c048ddf8SAnshuman Khandual if (pg_level[i].bits) 346c048ddf8SAnshuman Khandual for (j = 0; j < pg_level[i].num; j++) 347c048ddf8SAnshuman Khandual pg_level[i].mask |= pg_level[i].bits[j].mask; 348c048ddf8SAnshuman Khandual } 349c048ddf8SAnshuman Khandual 350c048ddf8SAnshuman Khandual static struct ptdump_info kernel_ptdump_info = { 351c048ddf8SAnshuman Khandual .mm = &init_mm, 352c048ddf8SAnshuman Khandual .markers = address_markers, 353c048ddf8SAnshuman Khandual .base_addr = PAGE_OFFSET, 354c048ddf8SAnshuman Khandual }; 355c048ddf8SAnshuman Khandual 356c048ddf8SAnshuman Khandual void ptdump_check_wx(void) 357c048ddf8SAnshuman Khandual { 358c048ddf8SAnshuman Khandual struct pg_state st = { 359c048ddf8SAnshuman Khandual .seq = NULL, 360c048ddf8SAnshuman Khandual .marker = (struct addr_marker[]) { 361c048ddf8SAnshuman Khandual { 0, NULL}, 362c048ddf8SAnshuman Khandual { -1, NULL}, 363c048ddf8SAnshuman Khandual }, 364c048ddf8SAnshuman Khandual .level = -1, 365c048ddf8SAnshuman Khandual .check_wx = true, 366c048ddf8SAnshuman Khandual .ptdump = { 367c048ddf8SAnshuman Khandual .note_page = note_page, 368c048ddf8SAnshuman Khandual .range = (struct ptdump_range[]) { 369c048ddf8SAnshuman Khandual {PAGE_OFFSET, ~0UL}, 370c048ddf8SAnshuman Khandual {0, 0} 371c048ddf8SAnshuman Khandual } 372c048ddf8SAnshuman Khandual } 373c048ddf8SAnshuman Khandual }; 374c048ddf8SAnshuman Khandual 375c048ddf8SAnshuman Khandual ptdump_walk_pgd(&st.ptdump, &init_mm, NULL); 376c048ddf8SAnshuman Khandual 377c048ddf8SAnshuman Khandual if (st.wx_pages || st.uxn_pages) 378c048ddf8SAnshuman Khandual pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n", 379c048ddf8SAnshuman Khandual st.wx_pages, st.uxn_pages); 380c048ddf8SAnshuman Khandual else 381c048ddf8SAnshuman Khandual pr_info("Checked W+X mappings: passed, no W+X pages found\n"); 382c048ddf8SAnshuman Khandual } 383c048ddf8SAnshuman Khandual 384c048ddf8SAnshuman Khandual static int ptdump_init(void) 385c048ddf8SAnshuman Khandual { 386c048ddf8SAnshuman Khandual address_markers[PAGE_END_NR].start_address = PAGE_END; 3870fea6e9aSAndrey Konovalov #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) 388c048ddf8SAnshuman Khandual address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START; 389c048ddf8SAnshuman Khandual #endif 390c048ddf8SAnshuman Khandual ptdump_initialize(); 391c048ddf8SAnshuman Khandual ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables"); 392c048ddf8SAnshuman Khandual return 0; 393c048ddf8SAnshuman Khandual } 394c048ddf8SAnshuman Khandual device_initcall(ptdump_init); 395