regulator: Add LTC3676 support
[cascardo/linux.git] / arch / arm64 / mm / dump.c
1 /*
2  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3  * Debug helper to dump the current kernel pagetables of the system
4  * so that we can see what the various memory ranges are set to.
5  *
6  * Derived from x86 and arm implementation:
7  * (C) Copyright 2008 Intel Corporation
8  *
9  * Author: Arjan van de Ven <arjan@linux.intel.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; version 2
14  * of the License.
15  */
16 #include <linux/debugfs.h>
17 #include <linux/errno.h>
18 #include <linux/fs.h>
19 #include <linux/io.h>
20 #include <linux/init.h>
21 #include <linux/mm.h>
22 #include <linux/sched.h>
23 #include <linux/seq_file.h>
24
25 #include <asm/fixmap.h>
26 #include <asm/kasan.h>
27 #include <asm/memory.h>
28 #include <asm/pgtable.h>
29 #include <asm/pgtable-hwdef.h>
30 #include <asm/ptdump.h>
31
32 static const struct addr_marker address_markers[] = {
33 #ifdef CONFIG_KASAN
34         { KASAN_SHADOW_START,           "Kasan shadow start" },
35         { KASAN_SHADOW_END,             "Kasan shadow end" },
36 #endif
37         { MODULES_VADDR,                "Modules start" },
38         { MODULES_END,                  "Modules end" },
39         { VMALLOC_START,                "vmalloc() Area" },
40         { VMALLOC_END,                  "vmalloc() End" },
41         { FIXADDR_START,                "Fixmap start" },
42         { FIXADDR_TOP,                  "Fixmap end" },
43         { PCI_IO_START,                 "PCI I/O start" },
44         { PCI_IO_END,                   "PCI I/O end" },
45 #ifdef CONFIG_SPARSEMEM_VMEMMAP
46         { VMEMMAP_START,                "vmemmap start" },
47         { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" },
48 #endif
49         { PAGE_OFFSET,                  "Linear Mapping" },
50         { -1,                           NULL },
51 };
52
53 /*
54  * The page dumper groups page table entries of the same type into a single
55  * description. It uses pg_state to track the range information while
56  * iterating over the pte entries. When the continuity is broken it then
57  * dumps out a description of the range.
58  */
59 struct pg_state {
60         struct seq_file *seq;
61         const struct addr_marker *marker;
62         unsigned long start_address;
63         unsigned level;
64         u64 current_prot;
65 };
66
67 struct prot_bits {
68         u64             mask;
69         u64             val;
70         const char      *set;
71         const char      *clear;
72 };
73
74 static const struct prot_bits pte_bits[] = {
75         {
76                 .mask   = PTE_VALID,
77                 .val    = PTE_VALID,
78                 .set    = " ",
79                 .clear  = "F",
80         }, {
81                 .mask   = PTE_USER,
82                 .val    = PTE_USER,
83                 .set    = "USR",
84                 .clear  = "   ",
85         }, {
86                 .mask   = PTE_RDONLY,
87                 .val    = PTE_RDONLY,
88                 .set    = "ro",
89                 .clear  = "RW",
90         }, {
91                 .mask   = PTE_PXN,
92                 .val    = PTE_PXN,
93                 .set    = "NX",
94                 .clear  = "x ",
95         }, {
96                 .mask   = PTE_SHARED,
97                 .val    = PTE_SHARED,
98                 .set    = "SHD",
99                 .clear  = "   ",
100         }, {
101                 .mask   = PTE_AF,
102                 .val    = PTE_AF,
103                 .set    = "AF",
104                 .clear  = "  ",
105         }, {
106                 .mask   = PTE_NG,
107                 .val    = PTE_NG,
108                 .set    = "NG",
109                 .clear  = "  ",
110         }, {
111                 .mask   = PTE_CONT,
112                 .val    = PTE_CONT,
113                 .set    = "CON",
114                 .clear  = "   ",
115         }, {
116                 .mask   = PTE_TABLE_BIT,
117                 .val    = PTE_TABLE_BIT,
118                 .set    = "   ",
119                 .clear  = "BLK",
120         }, {
121                 .mask   = PTE_UXN,
122                 .val    = PTE_UXN,
123                 .set    = "UXN",
124         }, {
125                 .mask   = PTE_ATTRINDX_MASK,
126                 .val    = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
127                 .set    = "DEVICE/nGnRnE",
128         }, {
129                 .mask   = PTE_ATTRINDX_MASK,
130                 .val    = PTE_ATTRINDX(MT_DEVICE_nGnRE),
131                 .set    = "DEVICE/nGnRE",
132         }, {
133                 .mask   = PTE_ATTRINDX_MASK,
134                 .val    = PTE_ATTRINDX(MT_DEVICE_GRE),
135                 .set    = "DEVICE/GRE",
136         }, {
137                 .mask   = PTE_ATTRINDX_MASK,
138                 .val    = PTE_ATTRINDX(MT_NORMAL_NC),
139                 .set    = "MEM/NORMAL-NC",
140         }, {
141                 .mask   = PTE_ATTRINDX_MASK,
142                 .val    = PTE_ATTRINDX(MT_NORMAL),
143                 .set    = "MEM/NORMAL",
144         }
145 };
146
147 struct pg_level {
148         const struct prot_bits *bits;
149         const char *name;
150         size_t num;
151         u64 mask;
152 };
153
154 static struct pg_level pg_level[] = {
155         {
156         }, { /* pgd */
157                 .name   = "PGD",
158                 .bits   = pte_bits,
159                 .num    = ARRAY_SIZE(pte_bits),
160         }, { /* pud */
161                 .name   = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD",
162                 .bits   = pte_bits,
163                 .num    = ARRAY_SIZE(pte_bits),
164         }, { /* pmd */
165                 .name   = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
166                 .bits   = pte_bits,
167                 .num    = ARRAY_SIZE(pte_bits),
168         }, { /* pte */
169                 .name   = "PTE",
170                 .bits   = pte_bits,
171                 .num    = ARRAY_SIZE(pte_bits),
172         },
173 };
174
175 static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
176                         size_t num)
177 {
178         unsigned i;
179
180         for (i = 0; i < num; i++, bits++) {
181                 const char *s;
182
183                 if ((st->current_prot & bits->mask) == bits->val)
184                         s = bits->set;
185                 else
186                         s = bits->clear;
187
188                 if (s)
189                         seq_printf(st->seq, " %s", s);
190         }
191 }
192
193 static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
194                                 u64 val)
195 {
196         static const char units[] = "KMGTPE";
197         u64 prot = val & pg_level[level].mask;
198
199         if (!st->level) {
200                 st->level = level;
201                 st->current_prot = prot;
202                 st->start_address = addr;
203                 seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
204         } else if (prot != st->current_prot || level != st->level ||
205                    addr >= st->marker[1].start_address) {
206                 const char *unit = units;
207                 unsigned long delta;
208
209                 if (st->current_prot) {
210                         seq_printf(st->seq, "0x%016lx-0x%016lx   ",
211                                    st->start_address, addr);
212
213                         delta = (addr - st->start_address) >> 10;
214                         while (!(delta & 1023) && unit[1]) {
215                                 delta >>= 10;
216                                 unit++;
217                         }
218                         seq_printf(st->seq, "%9lu%c %s", delta, *unit,
219                                    pg_level[st->level].name);
220                         if (pg_level[st->level].bits)
221                                 dump_prot(st, pg_level[st->level].bits,
222                                           pg_level[st->level].num);
223                         seq_puts(st->seq, "\n");
224                 }
225
226                 if (addr >= st->marker[1].start_address) {
227                         st->marker++;
228                         seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
229                 }
230
231                 st->start_address = addr;
232                 st->current_prot = prot;
233                 st->level = level;
234         }
235
236         if (addr >= st->marker[1].start_address) {
237                 st->marker++;
238                 seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
239         }
240
241 }
242
243 static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
244 {
245         pte_t *pte = pte_offset_kernel(pmd, 0);
246         unsigned long addr;
247         unsigned i;
248
249         for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
250                 addr = start + i * PAGE_SIZE;
251                 note_page(st, addr, 4, pte_val(*pte));
252         }
253 }
254
255 static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
256 {
257         pmd_t *pmd = pmd_offset(pud, 0);
258         unsigned long addr;
259         unsigned i;
260
261         for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
262                 addr = start + i * PMD_SIZE;
263                 if (pmd_none(*pmd) || pmd_sect(*pmd)) {
264                         note_page(st, addr, 3, pmd_val(*pmd));
265                 } else {
266                         BUG_ON(pmd_bad(*pmd));
267                         walk_pte(st, pmd, addr);
268                 }
269         }
270 }
271
272 static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
273 {
274         pud_t *pud = pud_offset(pgd, 0);
275         unsigned long addr;
276         unsigned i;
277
278         for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
279                 addr = start + i * PUD_SIZE;
280                 if (pud_none(*pud) || pud_sect(*pud)) {
281                         note_page(st, addr, 2, pud_val(*pud));
282                 } else {
283                         BUG_ON(pud_bad(*pud));
284                         walk_pmd(st, pud, addr);
285                 }
286         }
287 }
288
289 static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
290                      unsigned long start)
291 {
292         pgd_t *pgd = pgd_offset(mm, 0UL);
293         unsigned i;
294         unsigned long addr;
295
296         for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
297                 addr = start + i * PGDIR_SIZE;
298                 if (pgd_none(*pgd)) {
299                         note_page(st, addr, 1, pgd_val(*pgd));
300                 } else {
301                         BUG_ON(pgd_bad(*pgd));
302                         walk_pud(st, pgd, addr);
303                 }
304         }
305 }
306
307 static int ptdump_show(struct seq_file *m, void *v)
308 {
309         struct ptdump_info *info = m->private;
310         struct pg_state st = {
311                 .seq = m,
312                 .marker = info->markers,
313         };
314
315         walk_pgd(&st, info->mm, info->base_addr);
316
317         note_page(&st, 0, 0, 0);
318         return 0;
319 }
320
321 static int ptdump_open(struct inode *inode, struct file *file)
322 {
323         return single_open(file, ptdump_show, inode->i_private);
324 }
325
326 static const struct file_operations ptdump_fops = {
327         .open           = ptdump_open,
328         .read           = seq_read,
329         .llseek         = seq_lseek,
330         .release        = single_release,
331 };
332
333 int ptdump_register(struct ptdump_info *info, const char *name)
334 {
335         struct dentry *pe;
336         unsigned i, j;
337
338         for (i = 0; i < ARRAY_SIZE(pg_level); i++)
339                 if (pg_level[i].bits)
340                         for (j = 0; j < pg_level[i].num; j++)
341                                 pg_level[i].mask |= pg_level[i].bits[j].mask;
342
343         pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
344         return pe ? 0 : -ENOMEM;
345 }
346
347 static struct ptdump_info kernel_ptdump_info = {
348         .mm             = &init_mm,
349         .markers        = address_markers,
350         .base_addr      = VA_START,
351 };
352
353 static int ptdump_init(void)
354 {
355         return ptdump_register(&kernel_ptdump_info, "kernel_page_tables");
356 }
357 device_initcall(ptdump_init);