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-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright 2016, Rashmica Gupta, IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * This traverses the kernel virtual memory and dumps the pages that are in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * the hash pagetable, along with their flags to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * /sys/kernel/debug/kernel_hash_pagetable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * If radix is enabled then there is no hash page table and so no debugfs file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * is generated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/const.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <asm/plpar_wrappers.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <asm/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <asm/pgalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) struct pg_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	struct seq_file *seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	const struct addr_marker *marker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	unsigned long start_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	unsigned int level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	u64 current_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) struct addr_marker {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	unsigned long start_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	const char *name;
^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) 	{ 0,	"Start of kernel VM" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	{ 0,	"vmalloc() Area" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	{ 0,	"vmalloc() End" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	{ 0,	"isa I/O start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	{ 0,	"isa I/O end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	{ 0,	"phb I/O start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	{ 0,	"phb I/O end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	{ 0,	"I/O remap start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	{ 0,	"I/O remap end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	{ 0,	"vmemmap start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	{ -1,	NULL },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) struct flag_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	u64		mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	u64		val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	const char	*set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	const char	*clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	bool		is_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	int		shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) static const struct flag_info v_flag_array[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		.mask   = SLB_VSID_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		.val    = SLB_VSID_B_256M,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		.set    = "ssize: 256M",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 		.clear  = "ssize: 1T  ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		.mask	= HPTE_V_SECONDARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		.val	= HPTE_V_SECONDARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		.set	= "secondary",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		.clear	= "primary  ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		.mask	= HPTE_V_VALID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		.val	= HPTE_V_VALID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		.set	= "valid  ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		.clear	= "invalid",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		.mask	= HPTE_V_BOLTED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		.val	= HPTE_V_BOLTED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		.set	= "bolted",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		.clear	= "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	}
^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 const struct flag_info r_flag_array[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		.mask	= HPTE_R_PP0 | HPTE_R_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		.val	= PP_RWXX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		.set	= "prot:RW--",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		.mask	= HPTE_R_PP0 | HPTE_R_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		.val	= PP_RWRX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		.set	= "prot:RWR-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		.mask	= HPTE_R_PP0 | HPTE_R_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		.val	= PP_RWRW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		.set	= "prot:RWRW",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		.mask	= HPTE_R_PP0 | HPTE_R_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		.val	= PP_RXRX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		.set	= "prot:R-R-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		.mask	= HPTE_R_PP0 | HPTE_R_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		.val	= PP_RXXX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		.set	= "prot:R---",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		.mask	= HPTE_R_KEY_HI | HPTE_R_KEY_LO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		.val	= HPTE_R_KEY_HI | HPTE_R_KEY_LO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		.set	= "key",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		.clear	= "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		.is_val = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		.mask	= HPTE_R_R,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		.val	= HPTE_R_R,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		.set	= "ref",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		.clear	= "   ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		.mask	= HPTE_R_C,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		.val	= HPTE_R_C,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		.set	= "changed",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		.clear	= "       ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		.mask	= HPTE_R_N,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		.val	= HPTE_R_N,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		.set	= "no execute",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		.mask	= HPTE_R_WIMG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		.val	= HPTE_R_W,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		.set	= "writethru",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		.mask	= HPTE_R_WIMG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		.val	= HPTE_R_I,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		.set	= "no cache",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		.mask	= HPTE_R_WIMG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		.val	= HPTE_R_G,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		.set	= "guarded",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static int calculate_pagesize(struct pg_state *st, int ps, char s[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	static const char units[] = "BKMGTPE";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	const char *unit = units;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	while (ps > 9 && unit[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		ps -= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		unit++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	seq_printf(st->seq, "  %s_ps: %i%c\t", s, 1<<ps, *unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	return ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void dump_flag_info(struct pg_state *st, const struct flag_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		*flag, u64 pte, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	for (i = 0; i < num; i++, flag++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		const char *s = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		/* flag not defined so don't check it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		if (flag->mask == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		/* Some 'flags' are actually values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		if (flag->is_val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 			val = pte & flag->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 			if (flag->shift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 				val = val >> flag->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			seq_printf(st->seq, "  %s:%llx", flag->set, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			if ((pte & flag->mask) == flag->val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 				s = flag->set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 				s = flag->clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			if (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 				seq_printf(st->seq, "  %s", s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static void dump_hpte_info(struct pg_state *st, unsigned long ea, u64 v, u64 r,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		unsigned long rpn, int bps, int aps, unsigned long lp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	int aps_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	while (ea >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		st->marker++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	seq_printf(st->seq, "0x%lx:\t", ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	seq_printf(st->seq, "AVPN:%llx\t", HPTE_V_AVPN_VAL(v));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	dump_flag_info(st, v_flag_array, v, ARRAY_SIZE(v_flag_array));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	seq_printf(st->seq, "  rpn: %lx\t", rpn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	dump_flag_info(st, r_flag_array, r, ARRAY_SIZE(r_flag_array));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	calculate_pagesize(st, bps, "base");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	aps_index = calculate_pagesize(st, aps, "actual");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	if (aps_index != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 		seq_printf(st->seq, "LP enc: %lx", lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	seq_putc(st->seq, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static int native_find(unsigned long ea, int psize, bool primary, u64 *v, u64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		*r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	struct hash_pte *hptep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	unsigned long hash, vsid, vpn, hpte_group, want_v, hpte_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	int i, ssize = mmu_kernel_ssize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	unsigned long shift = mmu_psize_defs[psize].shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	/* calculate hash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	vsid = get_kernel_vsid(ea, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	vpn  = hpt_vpn(ea, vsid, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	hash = hpt_hash(vpn, shift, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	want_v = hpte_encode_avpn(vpn, psize, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	/* to check in the secondary hash table, we invert the hash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	if (!primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		hash = ~hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	for (i = 0; i < HPTES_PER_GROUP; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		hptep = htab_address + hpte_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		hpte_v = be64_to_cpu(hptep->v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			/* HPTE matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 			*v = be64_to_cpu(hptep->v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 			*r = be64_to_cpu(hptep->r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		++hpte_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static int pseries_find(unsigned long ea, int psize, bool primary, u64 *v, u64 *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	struct hash_pte ptes[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	unsigned long vsid, vpn, hash, hpte_group, want_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	int i, j, ssize = mmu_kernel_ssize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	long lpar_rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	unsigned long shift = mmu_psize_defs[psize].shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	/* calculate hash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	vsid = get_kernel_vsid(ea, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	vpn  = hpt_vpn(ea, vsid, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	hash = hpt_hash(vpn, shift, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	want_v = hpte_encode_avpn(vpn, psize, ssize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	/* to check in the secondary hash table, we invert the hash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	if (!primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		hash = ~hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	/* see if we can find an entry in the hpte with this hash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	for (i = 0; i < HPTES_PER_GROUP; i += 4, hpte_group += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		lpar_rc = plpar_pte_read_4(0, hpte_group, (void *)ptes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 		if (lpar_rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		for (j = 0; j < 4; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 			if (HPTE_V_COMPARE(ptes[j].v, want_v) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 					(ptes[j].v & HPTE_V_VALID)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 				/* HPTE matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 				*v = ptes[j].v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 				*r = ptes[j].r;
^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) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static void decode_r(int bps, unsigned long r, unsigned long *rpn, int *aps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		unsigned long *lp_bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	struct mmu_psize_def entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	unsigned long arpn, mask, lp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	int penc = -2, idx = 0, shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	/*.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	 * The LP field has 8 bits. Depending on the actual page size, some of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	 * these bits are concatenated with the APRN to get the RPN. The rest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	 * of the bits in the LP field is the LP value and is an encoding for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	 * the base page size and the actual page size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	 *  -	find the mmu entry for our base page size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	 *  -	go through all page encodings and use the associated mask to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	 *	find an encoding that matches our encoding in the LP field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	arpn = (r & HPTE_R_RPN) >> HPTE_R_RPN_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	lp = arpn & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	entry = mmu_psize_defs[bps];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	while (idx < MMU_PAGE_COUNT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		penc = entry.penc[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		if ((penc != -1) && (mmu_psize_defs[idx].shift)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 			shift = mmu_psize_defs[idx].shift -  HPTE_R_RPN_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			mask = (0x1 << (shift)) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			if ((lp & mask) == penc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 				*aps = mmu_psize_to_shift(idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 				*lp_bits = lp & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 				*rpn = arpn >> shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 				return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static int base_hpte_find(unsigned long ea, int psize, bool primary, u64 *v,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 			  u64 *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	if (IS_ENABLED(CONFIG_PPC_PSERIES) && firmware_has_feature(FW_FEATURE_LPAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		return pseries_find(ea, psize, primary, v, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	return native_find(ea, psize, primary, v, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static unsigned long hpte_find(struct pg_state *st, unsigned long ea, int psize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	unsigned long slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	u64 v  = 0, r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	unsigned long rpn, lp_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	int base_psize = 0, actual_psize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	if (ea < PAGE_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	/* Look in primary table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	slot = base_hpte_find(ea, psize, true, &v, &r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	/* Look in secondary table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	if (slot == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		slot = base_hpte_find(ea, psize, false, &v, &r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	/* No entry found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	if (slot == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	 * We found an entry in the hash page table:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	 *  - check that this has the same base page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	 *  - find the actual page size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	 *  - find the RPN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	base_psize = mmu_psize_to_shift(psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	if ((v & HPTE_V_LARGE) == HPTE_V_LARGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		decode_r(psize, r, &rpn, &actual_psize, &lp_bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		/* 4K actual page size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 		actual_psize = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		rpn = (r & HPTE_R_RPN) >> HPTE_R_RPN_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		/* In this case there are no LP bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		lp_bits = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	 * We didn't find a matching encoding, so the PTE we found isn't for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	 * this address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	if (actual_psize == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	dump_hpte_info(st, ea, v, r, rpn, base_psize, actual_psize, lp_bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	pte_t *pte = pte_offset_kernel(pmd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	unsigned long addr, pteval, psize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	int i, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		addr = start + i * PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		pteval = pte_val(*pte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		if (addr < VMALLOC_END)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 			psize = mmu_vmalloc_psize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			psize = mmu_io_psize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 		/* check for secret 4K mappings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		if (IS_ENABLED(CONFIG_PPC_64K_PAGES) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		    ((pteval & H_PAGE_COMBO) == H_PAGE_COMBO ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		     (pteval & H_PAGE_4K_PFN) == H_PAGE_4K_PFN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 			psize = mmu_io_psize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		/* check for hashpte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 		status = hpte_find(st, addr, psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		if (((pteval & H_PAGE_HASHPTE) != H_PAGE_HASHPTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 				&& (status != -1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 		/* found a hpte that is not in the linux page tables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 			seq_printf(st->seq, "page probably bolted before linux"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 				" pagetables were set: addr:%lx, pteval:%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 				addr, pteval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	pmd_t *pmd = pmd_offset(pud, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		addr = start + i * PMD_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		if (!pmd_none(*pmd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 			/* pmd exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 			walk_pte(st, pmd, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) static void walk_pud(struct pg_state *st, p4d_t *p4d, unsigned long start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 	pud_t *pud = pud_offset(p4d, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		addr = start + i * PUD_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		if (!pud_none(*pud))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 			/* pud exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 			walk_pmd(st, pud, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static void walk_p4d(struct pg_state *st, pgd_t *pgd, unsigned long start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	p4d_t *p4d = p4d_offset(pgd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 	for (i = 0; i < PTRS_PER_P4D; i++, p4d++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 		addr = start + i * P4D_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 		if (!p4d_none(*p4d))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 			/* p4d exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 			walk_pud(st, p4d, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) static void walk_pagetables(struct pg_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	pgd_t *pgd = pgd_offset_k(0UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	 * Traverse the linux pagetable structure and dump pages that are in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	 * the hash pagetable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		addr = KERN_VIRT_START + i * PGDIR_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		if (!pgd_none(*pgd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 			/* pgd exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 			walk_p4d(st, pgd, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static void walk_linearmapping(struct pg_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	 * Traverse the linear mapping section of virtual memory and dump pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	 * that are in the hash pagetable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	unsigned long psize = 1 << mmu_psize_defs[mmu_linear_psize].shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	for (addr = PAGE_OFFSET; addr < PAGE_OFFSET +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 			memblock_end_of_DRAM(); addr += psize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 		hpte_find(st, addr, mmu_linear_psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static void walk_vmemmap(struct pg_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	struct vmemmap_backing *ptr = vmemmap_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	if (!IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	 * Traverse the vmemmaped memory and dump pages that are in the hash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	 * pagetable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 	while (ptr->list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 		hpte_find(st, ptr->virt_addr, mmu_vmemmap_psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 		ptr = ptr->list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	seq_puts(st->seq, "---[ vmemmap end ]---\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static void populate_markers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	address_markers[0].start_address = PAGE_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	address_markers[1].start_address = VMALLOC_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	address_markers[2].start_address = VMALLOC_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	address_markers[3].start_address = ISA_IO_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	address_markers[4].start_address = ISA_IO_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	address_markers[5].start_address = PHB_IO_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	address_markers[6].start_address = PHB_IO_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	address_markers[7].start_address = IOREMAP_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	address_markers[8].start_address = IOREMAP_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	address_markers[9].start_address =  H_VMEMMAP_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) static int ptdump_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	struct pg_state st = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 		.seq = m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 		.start_address = PAGE_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 		.marker = address_markers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	 * Traverse the 0xc, 0xd and 0xf areas of the kernel virtual memory and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	 * dump pages that are in the hash pagetable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	walk_linearmapping(&st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	walk_pagetables(&st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	walk_vmemmap(&st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) static int ptdump_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	return single_open(file, ptdump_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) static const struct file_operations ptdump_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	.open		= ptdump_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	.read		= seq_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	.llseek		= seq_lseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	.release	= single_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static int ptdump_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	if (!radix_enabled()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 		populate_markers();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		debugfs_create_file("kernel_hash_pagetable", 0400, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 				    &ptdump_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) device_initcall(ptdump_init);