18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci * Debug helper to dump the current kernel pagetables of the system 58c2ecf20Sopenharmony_ci * so that we can see what the various memory ranges are set to. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Derived from x86 and arm implementation: 88c2ecf20Sopenharmony_ci * (C) Copyright 2008 Intel Corporation 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Author: Arjan van de Ven <arjan@linux.intel.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/fs.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/mm.h> 188c2ecf20Sopenharmony_ci#include <linux/ptdump.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/fixmap.h> 238c2ecf20Sopenharmony_ci#include <asm/kasan.h> 248c2ecf20Sopenharmony_ci#include <asm/memory.h> 258c2ecf20Sopenharmony_ci#include <asm/pgtable-hwdef.h> 268c2ecf20Sopenharmony_ci#include <asm/ptdump.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cienum address_markers_idx { 308c2ecf20Sopenharmony_ci PAGE_OFFSET_NR = 0, 318c2ecf20Sopenharmony_ci PAGE_END_NR, 328c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 338c2ecf20Sopenharmony_ci KASAN_START_NR, 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct addr_marker address_markers[] = { 388c2ecf20Sopenharmony_ci { PAGE_OFFSET, "Linear Mapping start" }, 398c2ecf20Sopenharmony_ci { 0 /* PAGE_END */, "Linear Mapping end" }, 408c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 418c2ecf20Sopenharmony_ci { 0 /* KASAN_SHADOW_START */, "Kasan shadow start" }, 428c2ecf20Sopenharmony_ci { KASAN_SHADOW_END, "Kasan shadow end" }, 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci { BPF_JIT_REGION_START, "BPF start" }, 458c2ecf20Sopenharmony_ci { BPF_JIT_REGION_END, "BPF end" }, 468c2ecf20Sopenharmony_ci { MODULES_VADDR, "Modules start" }, 478c2ecf20Sopenharmony_ci { MODULES_END, "Modules end" }, 488c2ecf20Sopenharmony_ci { VMALLOC_START, "vmalloc() area" }, 498c2ecf20Sopenharmony_ci { VMALLOC_END, "vmalloc() end" }, 508c2ecf20Sopenharmony_ci { FIXADDR_START, "Fixmap start" }, 518c2ecf20Sopenharmony_ci { FIXADDR_TOP, "Fixmap end" }, 528c2ecf20Sopenharmony_ci { PCI_IO_START, "PCI I/O start" }, 538c2ecf20Sopenharmony_ci { PCI_IO_END, "PCI I/O end" }, 548c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARSEMEM_VMEMMAP 558c2ecf20Sopenharmony_ci { VMEMMAP_START, "vmemmap start" }, 568c2ecf20Sopenharmony_ci { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" }, 578c2ecf20Sopenharmony_ci#endif 588c2ecf20Sopenharmony_ci { -1, NULL }, 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define pt_dump_seq_printf(m, fmt, args...) \ 628c2ecf20Sopenharmony_ci({ \ 638c2ecf20Sopenharmony_ci if (m) \ 648c2ecf20Sopenharmony_ci seq_printf(m, fmt, ##args); \ 658c2ecf20Sopenharmony_ci}) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define pt_dump_seq_puts(m, fmt) \ 688c2ecf20Sopenharmony_ci({ \ 698c2ecf20Sopenharmony_ci if (m) \ 708c2ecf20Sopenharmony_ci seq_printf(m, fmt); \ 718c2ecf20Sopenharmony_ci}) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * The page dumper groups page table entries of the same type into a single 758c2ecf20Sopenharmony_ci * description. It uses pg_state to track the range information while 768c2ecf20Sopenharmony_ci * iterating over the pte entries. When the continuity is broken it then 778c2ecf20Sopenharmony_ci * dumps out a description of the range. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistruct pg_state { 808c2ecf20Sopenharmony_ci struct ptdump_state ptdump; 818c2ecf20Sopenharmony_ci struct seq_file *seq; 828c2ecf20Sopenharmony_ci const struct addr_marker *marker; 838c2ecf20Sopenharmony_ci unsigned long start_address; 848c2ecf20Sopenharmony_ci int level; 858c2ecf20Sopenharmony_ci u64 current_prot; 868c2ecf20Sopenharmony_ci bool check_wx; 878c2ecf20Sopenharmony_ci unsigned long wx_pages; 888c2ecf20Sopenharmony_ci unsigned long uxn_pages; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct prot_bits { 928c2ecf20Sopenharmony_ci u64 mask; 938c2ecf20Sopenharmony_ci u64 val; 948c2ecf20Sopenharmony_ci const char *set; 958c2ecf20Sopenharmony_ci const char *clear; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct prot_bits pte_bits[] = { 998c2ecf20Sopenharmony_ci { 1008c2ecf20Sopenharmony_ci .mask = PTE_VALID, 1018c2ecf20Sopenharmony_ci .val = PTE_VALID, 1028c2ecf20Sopenharmony_ci .set = " ", 1038c2ecf20Sopenharmony_ci .clear = "F", 1048c2ecf20Sopenharmony_ci }, { 1058c2ecf20Sopenharmony_ci .mask = PTE_USER, 1068c2ecf20Sopenharmony_ci .val = PTE_USER, 1078c2ecf20Sopenharmony_ci .set = "USR", 1088c2ecf20Sopenharmony_ci .clear = " ", 1098c2ecf20Sopenharmony_ci }, { 1108c2ecf20Sopenharmony_ci .mask = PTE_RDONLY, 1118c2ecf20Sopenharmony_ci .val = PTE_RDONLY, 1128c2ecf20Sopenharmony_ci .set = "ro", 1138c2ecf20Sopenharmony_ci .clear = "RW", 1148c2ecf20Sopenharmony_ci }, { 1158c2ecf20Sopenharmony_ci .mask = PTE_PXN, 1168c2ecf20Sopenharmony_ci .val = PTE_PXN, 1178c2ecf20Sopenharmony_ci .set = "NX", 1188c2ecf20Sopenharmony_ci .clear = "x ", 1198c2ecf20Sopenharmony_ci }, { 1208c2ecf20Sopenharmony_ci .mask = PTE_SHARED, 1218c2ecf20Sopenharmony_ci .val = PTE_SHARED, 1228c2ecf20Sopenharmony_ci .set = "SHD", 1238c2ecf20Sopenharmony_ci .clear = " ", 1248c2ecf20Sopenharmony_ci }, { 1258c2ecf20Sopenharmony_ci .mask = PTE_AF, 1268c2ecf20Sopenharmony_ci .val = PTE_AF, 1278c2ecf20Sopenharmony_ci .set = "AF", 1288c2ecf20Sopenharmony_ci .clear = " ", 1298c2ecf20Sopenharmony_ci }, { 1308c2ecf20Sopenharmony_ci .mask = PTE_NG, 1318c2ecf20Sopenharmony_ci .val = PTE_NG, 1328c2ecf20Sopenharmony_ci .set = "NG", 1338c2ecf20Sopenharmony_ci .clear = " ", 1348c2ecf20Sopenharmony_ci }, { 1358c2ecf20Sopenharmony_ci .mask = PTE_CONT, 1368c2ecf20Sopenharmony_ci .val = PTE_CONT, 1378c2ecf20Sopenharmony_ci .set = "CON", 1388c2ecf20Sopenharmony_ci .clear = " ", 1398c2ecf20Sopenharmony_ci }, { 1408c2ecf20Sopenharmony_ci .mask = PTE_TABLE_BIT, 1418c2ecf20Sopenharmony_ci .val = PTE_TABLE_BIT, 1428c2ecf20Sopenharmony_ci .set = " ", 1438c2ecf20Sopenharmony_ci .clear = "BLK", 1448c2ecf20Sopenharmony_ci }, { 1458c2ecf20Sopenharmony_ci .mask = PTE_UXN, 1468c2ecf20Sopenharmony_ci .val = PTE_UXN, 1478c2ecf20Sopenharmony_ci .set = "UXN", 1488c2ecf20Sopenharmony_ci .clear = " ", 1498c2ecf20Sopenharmony_ci }, { 1508c2ecf20Sopenharmony_ci .mask = PTE_GP, 1518c2ecf20Sopenharmony_ci .val = PTE_GP, 1528c2ecf20Sopenharmony_ci .set = "GP", 1538c2ecf20Sopenharmony_ci .clear = " ", 1548c2ecf20Sopenharmony_ci }, { 1558c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1568c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE), 1578c2ecf20Sopenharmony_ci .set = "DEVICE/nGnRnE", 1588c2ecf20Sopenharmony_ci }, { 1598c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1608c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_DEVICE_nGnRE), 1618c2ecf20Sopenharmony_ci .set = "DEVICE/nGnRE", 1628c2ecf20Sopenharmony_ci }, { 1638c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1648c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_DEVICE_GRE), 1658c2ecf20Sopenharmony_ci .set = "DEVICE/GRE", 1668c2ecf20Sopenharmony_ci }, { 1678c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1688c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_NORMAL_NC), 1698c2ecf20Sopenharmony_ci .set = "MEM/NORMAL-NC", 1708c2ecf20Sopenharmony_ci }, { 1718c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1728c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_NORMAL), 1738c2ecf20Sopenharmony_ci .set = "MEM/NORMAL", 1748c2ecf20Sopenharmony_ci }, { 1758c2ecf20Sopenharmony_ci .mask = PTE_ATTRINDX_MASK, 1768c2ecf20Sopenharmony_ci .val = PTE_ATTRINDX(MT_NORMAL_TAGGED), 1778c2ecf20Sopenharmony_ci .set = "MEM/NORMAL-TAGGED", 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct pg_level { 1828c2ecf20Sopenharmony_ci const struct prot_bits *bits; 1838c2ecf20Sopenharmony_ci const char *name; 1848c2ecf20Sopenharmony_ci size_t num; 1858c2ecf20Sopenharmony_ci u64 mask; 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic struct pg_level pg_level[] = { 1898c2ecf20Sopenharmony_ci { /* pgd */ 1908c2ecf20Sopenharmony_ci .name = "PGD", 1918c2ecf20Sopenharmony_ci .bits = pte_bits, 1928c2ecf20Sopenharmony_ci .num = ARRAY_SIZE(pte_bits), 1938c2ecf20Sopenharmony_ci }, { /* p4d */ 1948c2ecf20Sopenharmony_ci .name = "P4D", 1958c2ecf20Sopenharmony_ci .bits = pte_bits, 1968c2ecf20Sopenharmony_ci .num = ARRAY_SIZE(pte_bits), 1978c2ecf20Sopenharmony_ci }, { /* pud */ 1988c2ecf20Sopenharmony_ci .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD", 1998c2ecf20Sopenharmony_ci .bits = pte_bits, 2008c2ecf20Sopenharmony_ci .num = ARRAY_SIZE(pte_bits), 2018c2ecf20Sopenharmony_ci }, { /* pmd */ 2028c2ecf20Sopenharmony_ci .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD", 2038c2ecf20Sopenharmony_ci .bits = pte_bits, 2048c2ecf20Sopenharmony_ci .num = ARRAY_SIZE(pte_bits), 2058c2ecf20Sopenharmony_ci }, { /* pte */ 2068c2ecf20Sopenharmony_ci .name = "PTE", 2078c2ecf20Sopenharmony_ci .bits = pte_bits, 2088c2ecf20Sopenharmony_ci .num = ARRAY_SIZE(pte_bits), 2098c2ecf20Sopenharmony_ci }, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void dump_prot(struct pg_state *st, const struct prot_bits *bits, 2138c2ecf20Sopenharmony_ci size_t num) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci unsigned i; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci for (i = 0; i < num; i++, bits++) { 2188c2ecf20Sopenharmony_ci const char *s; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if ((st->current_prot & bits->mask) == bits->val) 2218c2ecf20Sopenharmony_ci s = bits->set; 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci s = bits->clear; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (s) 2268c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, " %s", s); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic void note_prot_uxn(struct pg_state *st, unsigned long addr) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci if (!st->check_wx) 2338c2ecf20Sopenharmony_ci return; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if ((st->current_prot & PTE_UXN) == PTE_UXN) 2368c2ecf20Sopenharmony_ci return; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n", 2398c2ecf20Sopenharmony_ci (void *)st->start_address, (void *)st->start_address); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci st->uxn_pages += (addr - st->start_address) / PAGE_SIZE; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void note_prot_wx(struct pg_state *st, unsigned long addr) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci if (!st->check_wx) 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY) 2498c2ecf20Sopenharmony_ci return; 2508c2ecf20Sopenharmony_ci if ((st->current_prot & PTE_PXN) == PTE_PXN) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n", 2548c2ecf20Sopenharmony_ci (void *)st->start_address, (void *)st->start_address); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci st->wx_pages += (addr - st->start_address) / PAGE_SIZE; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, 2608c2ecf20Sopenharmony_ci u64 val) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); 2638c2ecf20Sopenharmony_ci static const char units[] = "KMGTPE"; 2648c2ecf20Sopenharmony_ci u64 prot = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (level >= 0) 2678c2ecf20Sopenharmony_ci prot = val & pg_level[level].mask; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (st->level == -1) { 2708c2ecf20Sopenharmony_ci st->level = level; 2718c2ecf20Sopenharmony_ci st->current_prot = prot; 2728c2ecf20Sopenharmony_ci st->start_address = addr; 2738c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 2748c2ecf20Sopenharmony_ci } else if (prot != st->current_prot || level != st->level || 2758c2ecf20Sopenharmony_ci addr >= st->marker[1].start_address) { 2768c2ecf20Sopenharmony_ci const char *unit = units; 2778c2ecf20Sopenharmony_ci unsigned long delta; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (st->current_prot) { 2808c2ecf20Sopenharmony_ci note_prot_uxn(st, addr); 2818c2ecf20Sopenharmony_ci note_prot_wx(st, addr); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ", 2858c2ecf20Sopenharmony_ci st->start_address, addr); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci delta = (addr - st->start_address) >> 10; 2888c2ecf20Sopenharmony_ci while (!(delta & 1023) && unit[1]) { 2898c2ecf20Sopenharmony_ci delta >>= 10; 2908c2ecf20Sopenharmony_ci unit++; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit, 2938c2ecf20Sopenharmony_ci pg_level[st->level].name); 2948c2ecf20Sopenharmony_ci if (st->current_prot && pg_level[st->level].bits) 2958c2ecf20Sopenharmony_ci dump_prot(st, pg_level[st->level].bits, 2968c2ecf20Sopenharmony_ci pg_level[st->level].num); 2978c2ecf20Sopenharmony_ci pt_dump_seq_puts(st->seq, "\n"); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (addr >= st->marker[1].start_address) { 3008c2ecf20Sopenharmony_ci st->marker++; 3018c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci st->start_address = addr; 3058c2ecf20Sopenharmony_ci st->current_prot = prot; 3068c2ecf20Sopenharmony_ci st->level = level; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (addr >= st->marker[1].start_address) { 3108c2ecf20Sopenharmony_ci st->marker++; 3118c2ecf20Sopenharmony_ci pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_civoid ptdump_walk(struct seq_file *s, struct ptdump_info *info) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci unsigned long end = ~0UL; 3198c2ecf20Sopenharmony_ci struct pg_state st; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (info->base_addr < TASK_SIZE_64) 3228c2ecf20Sopenharmony_ci end = TASK_SIZE_64; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci st = (struct pg_state){ 3258c2ecf20Sopenharmony_ci .seq = s, 3268c2ecf20Sopenharmony_ci .marker = info->markers, 3278c2ecf20Sopenharmony_ci .ptdump = { 3288c2ecf20Sopenharmony_ci .note_page = note_page, 3298c2ecf20Sopenharmony_ci .range = (struct ptdump_range[]){ 3308c2ecf20Sopenharmony_ci {info->base_addr, end}, 3318c2ecf20Sopenharmony_ci {0, 0} 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci }; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ptdump_walk_pgd(&st.ptdump, info->mm, NULL); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void ptdump_initialize(void) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci unsigned i, j; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pg_level); i++) 3448c2ecf20Sopenharmony_ci if (pg_level[i].bits) 3458c2ecf20Sopenharmony_ci for (j = 0; j < pg_level[i].num; j++) 3468c2ecf20Sopenharmony_ci pg_level[i].mask |= pg_level[i].bits[j].mask; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic struct ptdump_info kernel_ptdump_info = { 3508c2ecf20Sopenharmony_ci .mm = &init_mm, 3518c2ecf20Sopenharmony_ci .markers = address_markers, 3528c2ecf20Sopenharmony_ci .base_addr = PAGE_OFFSET, 3538c2ecf20Sopenharmony_ci}; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_civoid ptdump_check_wx(void) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct pg_state st = { 3588c2ecf20Sopenharmony_ci .seq = NULL, 3598c2ecf20Sopenharmony_ci .marker = (struct addr_marker[]) { 3608c2ecf20Sopenharmony_ci { 0, NULL}, 3618c2ecf20Sopenharmony_ci { -1, NULL}, 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci .level = -1, 3648c2ecf20Sopenharmony_ci .check_wx = true, 3658c2ecf20Sopenharmony_ci .ptdump = { 3668c2ecf20Sopenharmony_ci .note_page = note_page, 3678c2ecf20Sopenharmony_ci .range = (struct ptdump_range[]) { 3688c2ecf20Sopenharmony_ci {PAGE_OFFSET, ~0UL}, 3698c2ecf20Sopenharmony_ci {0, 0} 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci }; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ptdump_walk_pgd(&st.ptdump, &init_mm, NULL); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (st.wx_pages || st.uxn_pages) 3778c2ecf20Sopenharmony_ci pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n", 3788c2ecf20Sopenharmony_ci st.wx_pages, st.uxn_pages); 3798c2ecf20Sopenharmony_ci else 3808c2ecf20Sopenharmony_ci pr_info("Checked W+X mappings: passed, no W+X pages found\n"); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int ptdump_init(void) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci address_markers[PAGE_END_NR].start_address = PAGE_END; 3868c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 3878c2ecf20Sopenharmony_ci address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START; 3888c2ecf20Sopenharmony_ci#endif 3898c2ecf20Sopenharmony_ci ptdump_initialize(); 3908c2ecf20Sopenharmony_ci ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables"); 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_cidevice_initcall(ptdump_init); 394