Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #include <linux/set_memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #include <linux/ptdump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <linux/kasan.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <asm/ptdump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <asm/kasan.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) static unsigned long max_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) struct addr_marker {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 	unsigned long start_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 	const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) enum address_markers_idx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	IDENTITY_BEFORE_NR = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	IDENTITY_BEFORE_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	KERNEL_START_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	KERNEL_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	IDENTITY_AFTER_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	IDENTITY_AFTER_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #ifdef CONFIG_KASAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	KASAN_SHADOW_START_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	KASAN_SHADOW_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	VMEMMAP_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	VMEMMAP_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	VMALLOC_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	VMALLOC_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	MODULES_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	MODULES_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) static struct addr_marker address_markers[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	[IDENTITY_BEFORE_NR]	= {0, "Identity Mapping Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	[IDENTITY_BEFORE_END_NR] = {(unsigned long)_stext, "Identity Mapping End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	[KERNEL_START_NR]	= {(unsigned long)_stext, "Kernel Image Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	[KERNEL_END_NR]		= {(unsigned long)_end, "Kernel Image End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	[IDENTITY_AFTER_NR]	= {(unsigned long)_end, "Identity Mapping Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	[IDENTITY_AFTER_END_NR]	= {0, "Identity Mapping End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #ifdef CONFIG_KASAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	[KASAN_SHADOW_START_NR]	= {KASAN_SHADOW_START, "Kasan Shadow Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	[KASAN_SHADOW_END_NR]	= {KASAN_SHADOW_END, "Kasan Shadow End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	[VMEMMAP_NR]		= {0, "vmemmap Area Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	[VMEMMAP_END_NR]	= {0, "vmemmap Area End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	[VMALLOC_NR]		= {0, "vmalloc Area Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	[VMALLOC_END_NR]	= {0, "vmalloc Area End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	[MODULES_NR]		= {0, "Modules Area Start"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	[MODULES_END_NR]	= {0, "Modules Area End"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	{ -1, NULL }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) struct pg_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	struct ptdump_state ptdump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	struct seq_file *seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	int level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	unsigned int current_prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	bool check_wx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	unsigned long wx_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	unsigned long start_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	const struct addr_marker *marker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) #define pt_dump_seq_printf(m, fmt, args...)	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) ({						\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct seq_file *__m = (m);		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 						\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	if (__m)				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		seq_printf(__m, fmt, ##args);	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) #define pt_dump_seq_puts(m, fmt)		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) ({						\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	struct seq_file *__m = (m);		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 						\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	if (__m)				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		seq_printf(__m, fmt);		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static void print_prot(struct seq_file *m, unsigned int pr, int level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	static const char * const level_name[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		{ "ASCE", "PGD", "PUD", "PMD", "PTE" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	pt_dump_seq_printf(m, "%s ", level_name[level]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	if (pr & _PAGE_INVALID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		pt_dump_seq_printf(m, "I\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	pt_dump_seq_puts(m, (pr & _PAGE_PROTECT) ? "RO " : "RW ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	pt_dump_seq_puts(m, (pr & _PAGE_NOEXEC) ? "NX\n" : "X\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) static void note_prot_wx(struct pg_state *st, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #ifdef CONFIG_DEBUG_WX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	if (!st->check_wx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	if (st->current_prot & _PAGE_INVALID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	if (st->current_prot & _PAGE_PROTECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	if (st->current_prot & _PAGE_NOEXEC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	/* The first lowcore page is currently still W+X. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (addr == PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	WARN_ONCE(1, "s390/mm: Found insecure W+X mapping at address %pS\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		  (void *)st->start_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #endif /* CONFIG_DEBUG_WX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, u64 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	int width = sizeof(unsigned long) * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	static const char units[] = "KMGTPE";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	const char *unit = units;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	unsigned long delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	struct pg_state *st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	struct seq_file *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	unsigned int prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	st = container_of(pt_st, struct pg_state, ptdump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	m = st->seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	prot = val & (_PAGE_PROTECT | _PAGE_NOEXEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	if (level == 4 && (val & _PAGE_INVALID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		prot = _PAGE_INVALID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	/* For pmd_none() & friends val gets passed as zero. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	if (level != 4 && !val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		prot = _PAGE_INVALID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	/* Final flush from generic code. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	if (level == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		addr = max_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	if (st->level == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		pt_dump_seq_printf(m, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		st->start_address = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		st->current_prot = prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		st->level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	} else if (prot != st->current_prot || level != st->level ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		   addr >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		note_prot_wx(st, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		pt_dump_seq_printf(m, "0x%0*lx-0x%0*lx ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 				   width, st->start_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 				   width, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		delta = (addr - st->start_address) >> 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		while (!(delta & 0x3ff) && unit[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 			delta >>= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 			unit++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		pt_dump_seq_printf(m, "%9lu%c ", delta, *unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		print_prot(m, st->current_prot, st->level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		while (addr >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 			st->marker++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 			pt_dump_seq_printf(m, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		st->start_address = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		st->current_prot = prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		st->level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #ifdef CONFIG_DEBUG_WX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) void ptdump_check_wx(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	struct pg_state st = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		.ptdump = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			.note_page = note_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			.range = (struct ptdump_range[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 				{.start = 0, .end = max_addr},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 				{.start = 0, .end = 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		.seq = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		.level = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		.current_prot = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		.check_wx = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		.wx_pages = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		.start_address = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		.marker = (struct addr_marker[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 			{ .start_address =  0, .name = NULL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 			{ .start_address = -1, .name = NULL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	if (!MACHINE_HAS_NX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	if (st.wx_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n", st.wx_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		pr_info("Checked W+X mappings: passed, no unexpected W+X pages found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #endif /* CONFIG_DEBUG_WX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) #ifdef CONFIG_PTDUMP_DEBUGFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int ptdump_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	struct pg_state st = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		.ptdump = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			.note_page = note_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 			.range = (struct ptdump_range[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 				{.start = 0, .end = max_addr},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 				{.start = 0, .end = 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		.seq = m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		.level = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		.current_prot = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		.check_wx = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		.wx_pages = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		.start_address = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		.marker = address_markers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	get_online_mems();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	mutex_lock(&cpa_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	mutex_unlock(&cpa_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	put_online_mems();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) DEFINE_SHOW_ATTRIBUTE(ptdump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) #endif /* CONFIG_PTDUMP_DEBUGFS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)  * Heapsort from lib/sort.c is not a stable sorting algorithm, do a simple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)  * insertion sort to preserve the original order of markers with the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)  * start address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static void sort_address_markers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	struct addr_marker tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	for (i = 1; i < ARRAY_SIZE(address_markers) - 1; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		tmp = address_markers[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		for (j = i - 1; j >= 0 && address_markers[j].start_address > tmp.start_address; j--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 			address_markers[j + 1] = address_markers[j];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		address_markers[j + 1] = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static int pt_dump_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	 * Figure out the maximum virtual address being accessible with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	 * kernel ASCE. We need this to keep the page table walker functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	 * from accessing non-existent entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	max_addr = (S390_lowcore.kernel_asce & _REGION_ENTRY_TYPE_MASK) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	max_addr = 1UL << (max_addr * 11 + 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	address_markers[IDENTITY_AFTER_END_NR].start_address = memory_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	address_markers[MODULES_NR].start_address = MODULES_VADDR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	address_markers[MODULES_END_NR].start_address = MODULES_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	address_markers[VMEMMAP_NR].start_address = (unsigned long) vmemmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	address_markers[VMEMMAP_END_NR].start_address = (unsigned long)vmemmap + vmemmap_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	address_markers[VMALLOC_NR].start_address = VMALLOC_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	sort_address_markers();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) #ifdef CONFIG_PTDUMP_DEBUGFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) #endif /* CONFIG_PTDUMP_DEBUGFS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) device_initcall(pt_dump_init);