18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Debug helper to dump the current kernel pagetables of the system 48c2ecf20Sopenharmony_ci * so that we can see what the various memory ranges are set to. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (C) Copyright 2008 Intel Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Arjan van de Ven <arjan@linux.intel.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 128c2ecf20Sopenharmony_ci#include <linux/kasan.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 178c2ecf20Sopenharmony_ci#include <linux/highmem.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/ptdump.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/e820/types.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * The dumper groups pagetable entries of the same type into one, and for 258c2ecf20Sopenharmony_ci * that it needs to keep some state when walking, and flush this state 268c2ecf20Sopenharmony_ci * when a "break" in the continuity is found. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cistruct pg_state { 298c2ecf20Sopenharmony_ci struct ptdump_state ptdump; 308c2ecf20Sopenharmony_ci int level; 318c2ecf20Sopenharmony_ci pgprotval_t current_prot; 328c2ecf20Sopenharmony_ci pgprotval_t effective_prot; 338c2ecf20Sopenharmony_ci pgprotval_t prot_levels[5]; 348c2ecf20Sopenharmony_ci unsigned long start_address; 358c2ecf20Sopenharmony_ci const struct addr_marker *marker; 368c2ecf20Sopenharmony_ci unsigned long lines; 378c2ecf20Sopenharmony_ci bool to_dmesg; 388c2ecf20Sopenharmony_ci bool check_wx; 398c2ecf20Sopenharmony_ci unsigned long wx_pages; 408c2ecf20Sopenharmony_ci struct seq_file *seq; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct addr_marker { 448c2ecf20Sopenharmony_ci unsigned long start_address; 458c2ecf20Sopenharmony_ci const char *name; 468c2ecf20Sopenharmony_ci unsigned long max_lines; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Address space markers hints */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cienum address_markers_idx { 548c2ecf20Sopenharmony_ci USER_SPACE_NR = 0, 558c2ecf20Sopenharmony_ci KERNEL_SPACE_NR, 568c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 578c2ecf20Sopenharmony_ci LDT_NR, 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci LOW_KERNEL_NR, 608c2ecf20Sopenharmony_ci VMALLOC_START_NR, 618c2ecf20Sopenharmony_ci VMEMMAP_START_NR, 628c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 638c2ecf20Sopenharmony_ci KASAN_SHADOW_START_NR, 648c2ecf20Sopenharmony_ci KASAN_SHADOW_END_NR, 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci CPU_ENTRY_AREA_NR, 678c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ESPFIX64 688c2ecf20Sopenharmony_ci ESPFIX_START_NR, 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci#ifdef CONFIG_EFI 718c2ecf20Sopenharmony_ci EFI_END_NR, 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci HIGH_KERNEL_NR, 748c2ecf20Sopenharmony_ci MODULES_VADDR_NR, 758c2ecf20Sopenharmony_ci MODULES_END_NR, 768c2ecf20Sopenharmony_ci FIXADDR_START_NR, 778c2ecf20Sopenharmony_ci END_OF_SPACE_NR, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct addr_marker address_markers[] = { 818c2ecf20Sopenharmony_ci [USER_SPACE_NR] = { 0, "User Space" }, 828c2ecf20Sopenharmony_ci [KERNEL_SPACE_NR] = { (1UL << 63), "Kernel Space" }, 838c2ecf20Sopenharmony_ci [LOW_KERNEL_NR] = { 0UL, "Low Kernel Mapping" }, 848c2ecf20Sopenharmony_ci [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" }, 858c2ecf20Sopenharmony_ci [VMEMMAP_START_NR] = { 0UL, "Vmemmap" }, 868c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * These fields get initialized with the (dynamic) 898c2ecf20Sopenharmony_ci * KASAN_SHADOW_{START,END} values in pt_dump_init(). 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci [KASAN_SHADOW_START_NR] = { 0UL, "KASAN shadow" }, 928c2ecf20Sopenharmony_ci [KASAN_SHADOW_END_NR] = { 0UL, "KASAN shadow end" }, 938c2ecf20Sopenharmony_ci#endif 948c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 958c2ecf20Sopenharmony_ci [LDT_NR] = { 0UL, "LDT remap" }, 968c2ecf20Sopenharmony_ci#endif 978c2ecf20Sopenharmony_ci [CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" }, 988c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ESPFIX64 998c2ecf20Sopenharmony_ci [ESPFIX_START_NR] = { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci#ifdef CONFIG_EFI 1028c2ecf20Sopenharmony_ci [EFI_END_NR] = { EFI_VA_END, "EFI Runtime Services" }, 1038c2ecf20Sopenharmony_ci#endif 1048c2ecf20Sopenharmony_ci [HIGH_KERNEL_NR] = { __START_KERNEL_map, "High Kernel Mapping" }, 1058c2ecf20Sopenharmony_ci [MODULES_VADDR_NR] = { MODULES_VADDR, "Modules" }, 1068c2ecf20Sopenharmony_ci [MODULES_END_NR] = { MODULES_END, "End Modules" }, 1078c2ecf20Sopenharmony_ci [FIXADDR_START_NR] = { FIXADDR_START, "Fixmap Area" }, 1088c2ecf20Sopenharmony_ci [END_OF_SPACE_NR] = { -1, NULL } 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define INIT_PGD ((pgd_t *) &init_top_pgt) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#else /* CONFIG_X86_64 */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cienum address_markers_idx { 1168c2ecf20Sopenharmony_ci USER_SPACE_NR = 0, 1178c2ecf20Sopenharmony_ci KERNEL_SPACE_NR, 1188c2ecf20Sopenharmony_ci VMALLOC_START_NR, 1198c2ecf20Sopenharmony_ci VMALLOC_END_NR, 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM 1218c2ecf20Sopenharmony_ci PKMAP_BASE_NR, 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 1248c2ecf20Sopenharmony_ci LDT_NR, 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci CPU_ENTRY_AREA_NR, 1278c2ecf20Sopenharmony_ci FIXADDR_START_NR, 1288c2ecf20Sopenharmony_ci END_OF_SPACE_NR, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct addr_marker address_markers[] = { 1328c2ecf20Sopenharmony_ci [USER_SPACE_NR] = { 0, "User Space" }, 1338c2ecf20Sopenharmony_ci [KERNEL_SPACE_NR] = { PAGE_OFFSET, "Kernel Mapping" }, 1348c2ecf20Sopenharmony_ci [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" }, 1358c2ecf20Sopenharmony_ci [VMALLOC_END_NR] = { 0UL, "vmalloc() End" }, 1368c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM 1378c2ecf20Sopenharmony_ci [PKMAP_BASE_NR] = { 0UL, "Persistent kmap() Area" }, 1388c2ecf20Sopenharmony_ci#endif 1398c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 1408c2ecf20Sopenharmony_ci [LDT_NR] = { 0UL, "LDT remap" }, 1418c2ecf20Sopenharmony_ci#endif 1428c2ecf20Sopenharmony_ci [CPU_ENTRY_AREA_NR] = { 0UL, "CPU entry area" }, 1438c2ecf20Sopenharmony_ci [FIXADDR_START_NR] = { 0UL, "Fixmap area" }, 1448c2ecf20Sopenharmony_ci [END_OF_SPACE_NR] = { -1, NULL } 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define INIT_PGD (swapper_pg_dir) 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#endif /* !CONFIG_X86_64 */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* Multipliers for offsets within the PTEs */ 1528c2ecf20Sopenharmony_ci#define PTE_LEVEL_MULT (PAGE_SIZE) 1538c2ecf20Sopenharmony_ci#define PMD_LEVEL_MULT (PTRS_PER_PTE * PTE_LEVEL_MULT) 1548c2ecf20Sopenharmony_ci#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT) 1558c2ecf20Sopenharmony_ci#define P4D_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT) 1568c2ecf20Sopenharmony_ci#define PGD_LEVEL_MULT (PTRS_PER_P4D * P4D_LEVEL_MULT) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \ 1598c2ecf20Sopenharmony_ci({ \ 1608c2ecf20Sopenharmony_ci if (to_dmesg) \ 1618c2ecf20Sopenharmony_ci printk(KERN_INFO fmt, ##args); \ 1628c2ecf20Sopenharmony_ci else \ 1638c2ecf20Sopenharmony_ci if (m) \ 1648c2ecf20Sopenharmony_ci seq_printf(m, fmt, ##args); \ 1658c2ecf20Sopenharmony_ci}) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \ 1688c2ecf20Sopenharmony_ci({ \ 1698c2ecf20Sopenharmony_ci if (to_dmesg) \ 1708c2ecf20Sopenharmony_ci printk(KERN_CONT fmt, ##args); \ 1718c2ecf20Sopenharmony_ci else \ 1728c2ecf20Sopenharmony_ci if (m) \ 1738c2ecf20Sopenharmony_ci seq_printf(m, fmt, ##args); \ 1748c2ecf20Sopenharmony_ci}) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * Print a readable form of a pgprot_t to the seq_file 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void printk_prot(struct seq_file *m, pgprotval_t pr, int level, bool dmsg) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci static const char * const level_name[] = 1828c2ecf20Sopenharmony_ci { "pgd", "p4d", "pud", "pmd", "pte" }; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!(pr & _PAGE_PRESENT)) { 1858c2ecf20Sopenharmony_ci /* Not present */ 1868c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci if (pr & _PAGE_USER) 1898c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "USR "); 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 1928c2ecf20Sopenharmony_ci if (pr & _PAGE_RW) 1938c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "RW "); 1948c2ecf20Sopenharmony_ci else 1958c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "ro "); 1968c2ecf20Sopenharmony_ci if (pr & _PAGE_PWT) 1978c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "PWT "); 1988c2ecf20Sopenharmony_ci else 1998c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 2008c2ecf20Sopenharmony_ci if (pr & _PAGE_PCD) 2018c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "PCD "); 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Bit 7 has a different meaning on level 3 vs 4 */ 2068c2ecf20Sopenharmony_ci if (level <= 3 && pr & _PAGE_PSE) 2078c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "PSE "); 2088c2ecf20Sopenharmony_ci else 2098c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 2108c2ecf20Sopenharmony_ci if ((level == 4 && pr & _PAGE_PAT) || 2118c2ecf20Sopenharmony_ci ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE)) 2128c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "PAT "); 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 2158c2ecf20Sopenharmony_ci if (pr & _PAGE_GLOBAL) 2168c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "GLB "); 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, " "); 2198c2ecf20Sopenharmony_ci if (pr & _PAGE_NX) 2208c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "NX "); 2218c2ecf20Sopenharmony_ci else 2228c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "x "); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void note_wx(struct pg_state *st, unsigned long addr) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci unsigned long npages; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci npages = (addr - st->start_address) / PAGE_SIZE; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_BIOS 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * If PCI BIOS is enabled, the PCI BIOS area is forced to WX. 2368c2ecf20Sopenharmony_ci * Inform about it, but avoid the warning. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci if (pcibios_enabled && st->start_address >= PAGE_OFFSET + BIOS_BEGIN && 2398c2ecf20Sopenharmony_ci addr <= PAGE_OFFSET + BIOS_END) { 2408c2ecf20Sopenharmony_ci pr_warn_once("x86/mm: PCI BIOS W+X mapping %lu pages\n", npages); 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci#endif 2448c2ecf20Sopenharmony_ci /* Account the WX pages */ 2458c2ecf20Sopenharmony_ci st->wx_pages += npages; 2468c2ecf20Sopenharmony_ci WARN_ONCE(__supported_pte_mask & _PAGE_NX, 2478c2ecf20Sopenharmony_ci "x86/mm: Found insecure W+X mapping at address %pS\n", 2488c2ecf20Sopenharmony_ci (void *)st->start_address); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void effective_prot(struct ptdump_state *pt_st, int level, u64 val) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); 2548c2ecf20Sopenharmony_ci pgprotval_t prot = val & PTE_FLAGS_MASK; 2558c2ecf20Sopenharmony_ci pgprotval_t effective; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (level > 0) { 2588c2ecf20Sopenharmony_ci pgprotval_t higher_prot = st->prot_levels[level - 1]; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci effective = (higher_prot & prot & (_PAGE_USER | _PAGE_RW)) | 2618c2ecf20Sopenharmony_ci ((higher_prot | prot) & _PAGE_NX); 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci effective = prot; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci st->prot_levels[level] = effective; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* 2708c2ecf20Sopenharmony_ci * This function gets called on a break in a continuous series 2718c2ecf20Sopenharmony_ci * of PTE entries; the next one is different so we need to 2728c2ecf20Sopenharmony_ci * print what we collected so far. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_cistatic void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, 2758c2ecf20Sopenharmony_ci u64 val) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); 2788c2ecf20Sopenharmony_ci pgprotval_t new_prot, new_eff; 2798c2ecf20Sopenharmony_ci pgprotval_t cur, eff; 2808c2ecf20Sopenharmony_ci static const char units[] = "BKMGTPE"; 2818c2ecf20Sopenharmony_ci struct seq_file *m = st->seq; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci new_prot = val & PTE_FLAGS_MASK; 2848c2ecf20Sopenharmony_ci if (!val) 2858c2ecf20Sopenharmony_ci new_eff = 0; 2868c2ecf20Sopenharmony_ci else 2878c2ecf20Sopenharmony_ci new_eff = st->prot_levels[level]; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * If we have a "break" in the series, we need to flush the state that 2918c2ecf20Sopenharmony_ci * we have now. "break" is either changing perms, levels or 2928c2ecf20Sopenharmony_ci * address space marker. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci cur = st->current_prot; 2958c2ecf20Sopenharmony_ci eff = st->effective_prot; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (st->level == -1) { 2988c2ecf20Sopenharmony_ci /* First entry */ 2998c2ecf20Sopenharmony_ci st->current_prot = new_prot; 3008c2ecf20Sopenharmony_ci st->effective_prot = new_eff; 3018c2ecf20Sopenharmony_ci st->level = level; 3028c2ecf20Sopenharmony_ci st->marker = address_markers; 3038c2ecf20Sopenharmony_ci st->lines = 0; 3048c2ecf20Sopenharmony_ci pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", 3058c2ecf20Sopenharmony_ci st->marker->name); 3068c2ecf20Sopenharmony_ci } else if (new_prot != cur || new_eff != eff || level != st->level || 3078c2ecf20Sopenharmony_ci addr >= st->marker[1].start_address) { 3088c2ecf20Sopenharmony_ci const char *unit = units; 3098c2ecf20Sopenharmony_ci unsigned long delta; 3108c2ecf20Sopenharmony_ci int width = sizeof(unsigned long) * 2; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (st->check_wx && (eff & _PAGE_RW) && !(eff & _PAGE_NX)) 3138c2ecf20Sopenharmony_ci note_wx(st, addr); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * Now print the actual finished series 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci if (!st->marker->max_lines || 3198c2ecf20Sopenharmony_ci st->lines < st->marker->max_lines) { 3208c2ecf20Sopenharmony_ci pt_dump_seq_printf(m, st->to_dmesg, 3218c2ecf20Sopenharmony_ci "0x%0*lx-0x%0*lx ", 3228c2ecf20Sopenharmony_ci width, st->start_address, 3238c2ecf20Sopenharmony_ci width, addr); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci delta = addr - st->start_address; 3268c2ecf20Sopenharmony_ci while (!(delta & 1023) && unit[1]) { 3278c2ecf20Sopenharmony_ci delta >>= 10; 3288c2ecf20Sopenharmony_ci unit++; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", 3318c2ecf20Sopenharmony_ci delta, *unit); 3328c2ecf20Sopenharmony_ci printk_prot(m, st->current_prot, st->level, 3338c2ecf20Sopenharmony_ci st->to_dmesg); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci st->lines++; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* 3388c2ecf20Sopenharmony_ci * We print markers for special areas of address space, 3398c2ecf20Sopenharmony_ci * such as the start of vmalloc space etc. 3408c2ecf20Sopenharmony_ci * This helps in the interpretation. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (addr >= st->marker[1].start_address) { 3438c2ecf20Sopenharmony_ci if (st->marker->max_lines && 3448c2ecf20Sopenharmony_ci st->lines > st->marker->max_lines) { 3458c2ecf20Sopenharmony_ci unsigned long nskip = 3468c2ecf20Sopenharmony_ci st->lines - st->marker->max_lines; 3478c2ecf20Sopenharmony_ci pt_dump_seq_printf(m, st->to_dmesg, 3488c2ecf20Sopenharmony_ci "... %lu entr%s skipped ... \n", 3498c2ecf20Sopenharmony_ci nskip, 3508c2ecf20Sopenharmony_ci nskip == 1 ? "y" : "ies"); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci st->marker++; 3538c2ecf20Sopenharmony_ci st->lines = 0; 3548c2ecf20Sopenharmony_ci pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", 3558c2ecf20Sopenharmony_ci st->marker->name); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci st->start_address = addr; 3598c2ecf20Sopenharmony_ci st->current_prot = new_prot; 3608c2ecf20Sopenharmony_ci st->effective_prot = new_eff; 3618c2ecf20Sopenharmony_ci st->level = level; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic void ptdump_walk_pgd_level_core(struct seq_file *m, 3668c2ecf20Sopenharmony_ci struct mm_struct *mm, pgd_t *pgd, 3678c2ecf20Sopenharmony_ci bool checkwx, bool dmesg) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci const struct ptdump_range ptdump_ranges[] = { 3708c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 3718c2ecf20Sopenharmony_ci {0, PTRS_PER_PGD * PGD_LEVEL_MULT / 2}, 3728c2ecf20Sopenharmony_ci {GUARD_HOLE_END_ADDR, ~0UL}, 3738c2ecf20Sopenharmony_ci#else 3748c2ecf20Sopenharmony_ci {0, ~0UL}, 3758c2ecf20Sopenharmony_ci#endif 3768c2ecf20Sopenharmony_ci {0, 0} 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci struct pg_state st = { 3808c2ecf20Sopenharmony_ci .ptdump = { 3818c2ecf20Sopenharmony_ci .note_page = note_page, 3828c2ecf20Sopenharmony_ci .effective_prot = effective_prot, 3838c2ecf20Sopenharmony_ci .range = ptdump_ranges 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci .level = -1, 3868c2ecf20Sopenharmony_ci .to_dmesg = dmesg, 3878c2ecf20Sopenharmony_ci .check_wx = checkwx, 3888c2ecf20Sopenharmony_ci .seq = m 3898c2ecf20Sopenharmony_ci }; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ptdump_walk_pgd(&st.ptdump, mm, pgd); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!checkwx) 3948c2ecf20Sopenharmony_ci return; 3958c2ecf20Sopenharmony_ci if (st.wx_pages) 3968c2ecf20Sopenharmony_ci pr_info("x86/mm: Checked W+X mappings: FAILED, %lu W+X pages found.\n", 3978c2ecf20Sopenharmony_ci st.wx_pages); 3988c2ecf20Sopenharmony_ci else 3998c2ecf20Sopenharmony_ci pr_info("x86/mm: Checked W+X mappings: passed, no W+X pages found.\n"); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_civoid ptdump_walk_pgd_level(struct seq_file *m, struct mm_struct *mm) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci ptdump_walk_pgd_level_core(m, mm, mm->pgd, false, true); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_civoid ptdump_walk_pgd_level_debugfs(struct seq_file *m, struct mm_struct *mm, 4088c2ecf20Sopenharmony_ci bool user) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci pgd_t *pgd = mm->pgd; 4118c2ecf20Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_ISOLATION 4128c2ecf20Sopenharmony_ci if (user && boot_cpu_has(X86_FEATURE_PTI)) 4138c2ecf20Sopenharmony_ci pgd = kernel_to_user_pgdp(pgd); 4148c2ecf20Sopenharmony_ci#endif 4158c2ecf20Sopenharmony_ci ptdump_walk_pgd_level_core(m, mm, pgd, false, false); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_civoid ptdump_walk_user_pgd_level_checkwx(void) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci#ifdef CONFIG_PAGE_TABLE_ISOLATION 4228c2ecf20Sopenharmony_ci pgd_t *pgd = INIT_PGD; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (!(__supported_pte_mask & _PAGE_NX) || 4258c2ecf20Sopenharmony_ci !boot_cpu_has(X86_FEATURE_PTI)) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci pr_info("x86/mm: Checking user space page tables\n"); 4298c2ecf20Sopenharmony_ci pgd = kernel_to_user_pgdp(pgd); 4308c2ecf20Sopenharmony_ci ptdump_walk_pgd_level_core(NULL, &init_mm, pgd, true, false); 4318c2ecf20Sopenharmony_ci#endif 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_civoid ptdump_walk_pgd_level_checkwx(void) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci ptdump_walk_pgd_level_core(NULL, &init_mm, INIT_PGD, true, false); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int __init pt_dump_init(void) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * Various markers are not compile-time constants, so assign them 4438c2ecf20Sopenharmony_ci * here. 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 4468c2ecf20Sopenharmony_ci address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET; 4478c2ecf20Sopenharmony_ci address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; 4488c2ecf20Sopenharmony_ci address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START; 4498c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 4508c2ecf20Sopenharmony_ci address_markers[LDT_NR].start_address = LDT_BASE_ADDR; 4518c2ecf20Sopenharmony_ci#endif 4528c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN 4538c2ecf20Sopenharmony_ci address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START; 4548c2ecf20Sopenharmony_ci address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END; 4558c2ecf20Sopenharmony_ci#endif 4568c2ecf20Sopenharmony_ci#endif 4578c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 4588c2ecf20Sopenharmony_ci address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; 4598c2ecf20Sopenharmony_ci address_markers[VMALLOC_END_NR].start_address = VMALLOC_END; 4608c2ecf20Sopenharmony_ci# ifdef CONFIG_HIGHMEM 4618c2ecf20Sopenharmony_ci address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE; 4628c2ecf20Sopenharmony_ci# endif 4638c2ecf20Sopenharmony_ci address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; 4648c2ecf20Sopenharmony_ci address_markers[CPU_ENTRY_AREA_NR].start_address = CPU_ENTRY_AREA_BASE; 4658c2ecf20Sopenharmony_ci# ifdef CONFIG_MODIFY_LDT_SYSCALL 4668c2ecf20Sopenharmony_ci address_markers[LDT_NR].start_address = LDT_BASE_ADDR; 4678c2ecf20Sopenharmony_ci# endif 4688c2ecf20Sopenharmony_ci#endif 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci__initcall(pt_dump_init); 472