^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);