2019-06-01 10:08:55 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2014-11-26 00:28:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
|
|
|
* Debug helper to dump the current kernel pagetables of the system
|
|
|
|
* so that we can see what the various memory ranges are set to.
|
|
|
|
*
|
|
|
|
* Derived from x86 and arm implementation:
|
|
|
|
* (C) Copyright 2008 Intel Corporation
|
|
|
|
*
|
|
|
|
* Author: Arjan van de Ven <arjan@linux.intel.com>
|
|
|
|
*/
|
|
|
|
#include <linux/debugfs.h>
|
2015-01-22 18:20:36 +00:00
|
|
|
#include <linux/errno.h>
|
2014-11-26 00:28:39 +00:00
|
|
|
#include <linux/fs.h>
|
2015-01-22 20:52:10 +00:00
|
|
|
#include <linux/io.h>
|
2015-01-22 18:20:36 +00:00
|
|
|
#include <linux/init.h>
|
2014-11-26 00:28:39 +00:00
|
|
|
#include <linux/mm.h>
|
2020-02-03 17:36:29 -08:00
|
|
|
#include <linux/ptdump.h>
|
2014-11-26 00:28:39 +00:00
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
|
|
|
|
#include <asm/fixmap.h>
|
2016-04-22 18:48:04 +02:00
|
|
|
#include <asm/kasan.h>
|
2015-01-22 18:20:36 +00:00
|
|
|
#include <asm/memory.h>
|
|
|
|
#include <asm/pgtable-hwdef.h>
|
2016-05-31 14:49:01 +01:00
|
|
|
#include <asm/ptdump.h>
|
2014-11-26 00:28:39 +00:00
|
|
|
|
2019-08-07 16:55:16 +01:00
|
|
|
|
2016-10-27 09:27:32 -07:00
|
|
|
#define pt_dump_seq_printf(m, fmt, args...) \
|
|
|
|
({ \
|
|
|
|
if (m) \
|
|
|
|
seq_printf(m, fmt, ##args); \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define pt_dump_seq_puts(m, fmt) \
|
|
|
|
({ \
|
|
|
|
if (m) \
|
|
|
|
seq_printf(m, fmt); \
|
|
|
|
})
|
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
static const struct ptdump_prot_bits pte_bits[] = {
|
2014-11-26 00:28:39 +00:00
|
|
|
{
|
2016-02-05 16:24:48 -08:00
|
|
|
.mask = PTE_VALID,
|
|
|
|
.val = PTE_VALID,
|
|
|
|
.set = " ",
|
|
|
|
.clear = "F",
|
|
|
|
}, {
|
2014-11-26 00:28:39 +00:00
|
|
|
.mask = PTE_USER,
|
|
|
|
.val = PTE_USER,
|
|
|
|
.set = "USR",
|
|
|
|
.clear = " ",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_RDONLY,
|
|
|
|
.val = PTE_RDONLY,
|
|
|
|
.set = "ro",
|
|
|
|
.clear = "RW",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_PXN,
|
|
|
|
.val = PTE_PXN,
|
|
|
|
.set = "NX",
|
|
|
|
.clear = "x ",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_SHARED,
|
|
|
|
.val = PTE_SHARED,
|
|
|
|
.set = "SHD",
|
|
|
|
.clear = " ",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_AF,
|
|
|
|
.val = PTE_AF,
|
|
|
|
.set = "AF",
|
|
|
|
.clear = " ",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_NG,
|
|
|
|
.val = PTE_NG,
|
|
|
|
.set = "NG",
|
|
|
|
.clear = " ",
|
2015-10-07 12:00:23 -05:00
|
|
|
}, {
|
|
|
|
.mask = PTE_CONT,
|
|
|
|
.val = PTE_CONT,
|
|
|
|
.set = "CON",
|
|
|
|
.clear = " ",
|
|
|
|
}, {
|
2024-11-05 10:11:54 +05:30
|
|
|
.mask = PTE_TABLE_BIT | PTE_VALID,
|
|
|
|
.val = PTE_VALID,
|
|
|
|
.set = "BLK",
|
|
|
|
.clear = " ",
|
2014-11-26 00:28:39 +00:00
|
|
|
}, {
|
|
|
|
.mask = PTE_UXN,
|
|
|
|
.val = PTE_UXN,
|
|
|
|
.set = "UXN",
|
2019-11-21 13:51:32 +00:00
|
|
|
.clear = " ",
|
2020-03-16 16:50:53 +00:00
|
|
|
}, {
|
|
|
|
.mask = PTE_GP,
|
|
|
|
.val = PTE_GP,
|
|
|
|
.set = "GP",
|
|
|
|
.clear = " ",
|
2014-11-26 00:28:39 +00:00
|
|
|
}, {
|
|
|
|
.mask = PTE_ATTRINDX_MASK,
|
|
|
|
.val = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
|
|
|
|
.set = "DEVICE/nGnRnE",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_ATTRINDX_MASK,
|
|
|
|
.val = PTE_ATTRINDX(MT_DEVICE_nGnRE),
|
|
|
|
.set = "DEVICE/nGnRE",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_ATTRINDX_MASK,
|
|
|
|
.val = PTE_ATTRINDX(MT_NORMAL_NC),
|
|
|
|
.set = "MEM/NORMAL-NC",
|
|
|
|
}, {
|
|
|
|
.mask = PTE_ATTRINDX_MASK,
|
|
|
|
.val = PTE_ATTRINDX(MT_NORMAL),
|
|
|
|
.set = "MEM/NORMAL",
|
2019-11-27 09:51:13 +00:00
|
|
|
}, {
|
|
|
|
.mask = PTE_ATTRINDX_MASK,
|
|
|
|
.val = PTE_ATTRINDX(MT_NORMAL_TAGGED),
|
|
|
|
.set = "MEM/NORMAL-TAGGED",
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-09-09 12:47:19 +00:00
|
|
|
static struct ptdump_pg_level kernel_pg_levels[] __ro_after_init = {
|
2020-02-03 17:36:38 -08:00
|
|
|
{ /* pgd */
|
arm64: mm: dump: log span level
The page table dump code logs spans of entries at the same level
(pgd/pud/pmd/pte) which have the same attributes. While we log the
(decoded) attributes, we don't log the level, which leaves the output
ambiguous and/or confusing in some cases.
For example:
0xffff800800000000-0xffff800980000000 6G RW NX SHD AF BLK UXN MEM/NORMAL
If using 4K pages, this may describe a span of 6 1G block entries at the
PGD/PUD level, or 3072 2M block entries at the PMD level.
This patch adds the page table level to each output line, removing this
ambiguity. For the example above, this will produce:
0xffffffc800000000-0xffffffc980000000 6G PUD RW NX SHD AF BLK UXN MEM/NORMAL
When 3 level tables are in use, and we use the asm-generic/nopud.h
definitions, the dump code treats each entry in the PGD as a 1 element
table at the PUD level, and logs spans as being PUDs, which can be
confusing. To counteract this, the "PUD" mnemonic is replaced with "PGD"
when CONFIG_PGTABLE_LEVELS <= 3. Likewise for "PMD" when
CONFIG_PGTABLE_LEVELS <= 2.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Huang Shijie <shijie.huang@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Steve Capper <steve.capper@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2016-05-31 14:49:02 +01:00
|
|
|
.name = "PGD",
|
2014-11-26 00:28:39 +00:00
|
|
|
.bits = pte_bits,
|
|
|
|
.num = ARRAY_SIZE(pte_bits),
|
2020-02-03 17:36:29 -08:00
|
|
|
}, { /* p4d */
|
|
|
|
.name = "P4D",
|
|
|
|
.bits = pte_bits,
|
|
|
|
.num = ARRAY_SIZE(pte_bits),
|
2014-11-26 00:28:39 +00:00
|
|
|
}, { /* pud */
|
2024-02-14 13:29:24 +01:00
|
|
|
.name = "PUD",
|
2014-11-26 00:28:39 +00:00
|
|
|
.bits = pte_bits,
|
|
|
|
.num = ARRAY_SIZE(pte_bits),
|
|
|
|
}, { /* pmd */
|
2024-02-14 13:29:24 +01:00
|
|
|
.name = "PMD",
|
2014-11-26 00:28:39 +00:00
|
|
|
.bits = pte_bits,
|
|
|
|
.num = ARRAY_SIZE(pte_bits),
|
|
|
|
}, { /* pte */
|
arm64: mm: dump: log span level
The page table dump code logs spans of entries at the same level
(pgd/pud/pmd/pte) which have the same attributes. While we log the
(decoded) attributes, we don't log the level, which leaves the output
ambiguous and/or confusing in some cases.
For example:
0xffff800800000000-0xffff800980000000 6G RW NX SHD AF BLK UXN MEM/NORMAL
If using 4K pages, this may describe a span of 6 1G block entries at the
PGD/PUD level, or 3072 2M block entries at the PMD level.
This patch adds the page table level to each output line, removing this
ambiguity. For the example above, this will produce:
0xffffffc800000000-0xffffffc980000000 6G PUD RW NX SHD AF BLK UXN MEM/NORMAL
When 3 level tables are in use, and we use the asm-generic/nopud.h
definitions, the dump code treats each entry in the PGD as a 1 element
table at the PUD level, and logs spans as being PUDs, which can be
confusing. To counteract this, the "PUD" mnemonic is replaced with "PGD"
when CONFIG_PGTABLE_LEVELS <= 3. Likewise for "PMD" when
CONFIG_PGTABLE_LEVELS <= 2.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Huang Shijie <shijie.huang@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Steve Capper <steve.capper@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2016-05-31 14:49:02 +01:00
|
|
|
.name = "PTE",
|
2014-11-26 00:28:39 +00:00
|
|
|
.bits = pte_bits,
|
|
|
|
.num = ARRAY_SIZE(pte_bits),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
static void dump_prot(struct ptdump_pg_state *st, const struct ptdump_prot_bits *bits,
|
2014-11-26 00:28:39 +00:00
|
|
|
size_t num)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < num; i++, bits++) {
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
if ((st->current_prot & bits->mask) == bits->val)
|
|
|
|
s = bits->set;
|
|
|
|
else
|
|
|
|
s = bits->clear;
|
|
|
|
|
|
|
|
if (s)
|
2016-10-27 09:27:32 -07:00
|
|
|
pt_dump_seq_printf(st->seq, " %s", s);
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
static void note_prot_uxn(struct ptdump_pg_state *st, unsigned long addr)
|
2016-10-27 09:27:34 -07:00
|
|
|
{
|
|
|
|
if (!st->check_wx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((st->current_prot & PTE_UXN) == PTE_UXN)
|
|
|
|
return;
|
|
|
|
|
|
|
|
WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n",
|
|
|
|
(void *)st->start_address, (void *)st->start_address);
|
|
|
|
|
|
|
|
st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
static void note_prot_wx(struct ptdump_pg_state *st, unsigned long addr)
|
2016-10-27 09:27:34 -07:00
|
|
|
{
|
|
|
|
if (!st->check_wx)
|
|
|
|
return;
|
|
|
|
if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY)
|
|
|
|
return;
|
|
|
|
if ((st->current_prot & PTE_PXN) == PTE_PXN)
|
|
|
|
return;
|
|
|
|
|
|
|
|
WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
|
|
|
|
(void *)st->start_address, (void *)st->start_address);
|
|
|
|
|
|
|
|
st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
|
|
|
|
u64 val)
|
2014-11-26 00:28:39 +00:00
|
|
|
{
|
2024-09-09 12:47:18 +00:00
|
|
|
struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
|
2024-09-09 12:47:19 +00:00
|
|
|
struct ptdump_pg_level *pg_level = st->pg_level;
|
2014-11-26 00:28:39 +00:00
|
|
|
static const char units[] = "KMGTPE";
|
2020-02-03 17:36:29 -08:00
|
|
|
u64 prot = 0;
|
|
|
|
|
2024-02-14 13:29:24 +01:00
|
|
|
/* check if the current level has been folded dynamically */
|
2024-09-09 12:47:20 +00:00
|
|
|
if (st->mm && ((level == 1 && mm_p4d_folded(st->mm)) ||
|
|
|
|
(level == 2 && mm_pud_folded(st->mm))))
|
2024-02-14 13:29:24 +01:00
|
|
|
level = 0;
|
|
|
|
|
2020-02-03 17:36:29 -08:00
|
|
|
if (level >= 0)
|
|
|
|
prot = val & pg_level[level].mask;
|
2014-11-26 00:28:39 +00:00
|
|
|
|
2020-02-03 17:36:38 -08:00
|
|
|
if (st->level == -1) {
|
2014-11-26 00:28:39 +00:00
|
|
|
st->level = level;
|
|
|
|
st->current_prot = prot;
|
|
|
|
st->start_address = addr;
|
2016-10-27 09:27:32 -07:00
|
|
|
pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
|
2014-11-26 00:28:39 +00:00
|
|
|
} else if (prot != st->current_prot || level != st->level ||
|
|
|
|
addr >= st->marker[1].start_address) {
|
|
|
|
const char *unit = units;
|
|
|
|
unsigned long delta;
|
|
|
|
|
|
|
|
if (st->current_prot) {
|
2016-10-27 09:27:34 -07:00
|
|
|
note_prot_uxn(st, addr);
|
|
|
|
note_prot_wx(st, addr);
|
2020-02-03 17:36:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ",
|
2014-11-26 00:28:39 +00:00
|
|
|
st->start_address, addr);
|
|
|
|
|
2020-02-03 17:36:34 -08:00
|
|
|
delta = (addr - st->start_address) >> 10;
|
|
|
|
while (!(delta & 1023) && unit[1]) {
|
|
|
|
delta >>= 10;
|
|
|
|
unit++;
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
2020-02-03 17:36:34 -08:00
|
|
|
pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
|
|
|
|
pg_level[st->level].name);
|
|
|
|
if (st->current_prot && pg_level[st->level].bits)
|
|
|
|
dump_prot(st, pg_level[st->level].bits,
|
|
|
|
pg_level[st->level].num);
|
|
|
|
pt_dump_seq_puts(st->seq, "\n");
|
2014-11-26 00:28:39 +00:00
|
|
|
|
|
|
|
if (addr >= st->marker[1].start_address) {
|
|
|
|
st->marker++;
|
2016-10-27 09:27:32 -07:00
|
|
|
pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
st->start_address = addr;
|
|
|
|
st->current_prot = prot;
|
|
|
|
st->level = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr >= st->marker[1].start_address) {
|
|
|
|
st->marker++;
|
2016-10-27 09:27:32 -07:00
|
|
|
pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-03 17:36:29 -08:00
|
|
|
void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
|
2014-11-26 00:28:39 +00:00
|
|
|
{
|
2020-02-03 17:36:29 -08:00
|
|
|
unsigned long end = ~0UL;
|
2024-09-09 12:47:18 +00:00
|
|
|
struct ptdump_pg_state st;
|
2014-11-26 00:28:39 +00:00
|
|
|
|
2020-02-03 17:36:29 -08:00
|
|
|
if (info->base_addr < TASK_SIZE_64)
|
|
|
|
end = TASK_SIZE_64;
|
2014-11-26 00:28:39 +00:00
|
|
|
|
2024-09-09 12:47:18 +00:00
|
|
|
st = (struct ptdump_pg_state){
|
2020-02-03 17:36:29 -08:00
|
|
|
.seq = s,
|
2016-05-31 14:49:01 +01:00
|
|
|
.marker = info->markers,
|
2024-02-14 13:29:24 +01:00
|
|
|
.mm = info->mm,
|
2024-09-09 12:47:19 +00:00
|
|
|
.pg_level = &kernel_pg_levels[0],
|
2021-02-02 23:07:49 +08:00
|
|
|
.level = -1,
|
2020-02-03 17:36:29 -08:00
|
|
|
.ptdump = {
|
|
|
|
.note_page = note_page,
|
|
|
|
.range = (struct ptdump_range[]){
|
|
|
|
{info->base_addr, end},
|
|
|
|
{0, 0}
|
|
|
|
}
|
|
|
|
}
|
2014-11-26 00:28:39 +00:00
|
|
|
};
|
|
|
|
|
2020-02-03 17:36:42 -08:00
|
|
|
ptdump_walk_pgd(&st.ptdump, info->mm, NULL);
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 13:54:49 +08:00
|
|
|
static void __init ptdump_initialize(void)
|
2014-11-26 00:28:39 +00:00
|
|
|
{
|
|
|
|
unsigned i, j;
|
|
|
|
|
2024-09-09 12:47:19 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(kernel_pg_levels); i++)
|
|
|
|
if (kernel_pg_levels[i].bits)
|
|
|
|
for (j = 0; j < kernel_pg_levels[i].num; j++)
|
|
|
|
kernel_pg_levels[i].mask |= kernel_pg_levels[i].bits[j].mask;
|
2014-11-26 00:28:39 +00:00
|
|
|
}
|
2016-05-31 14:49:01 +01:00
|
|
|
|
2023-12-13 09:40:28 +01:00
|
|
|
static struct ptdump_info kernel_ptdump_info __ro_after_init = {
|
2016-05-31 14:49:01 +01:00
|
|
|
.mm = &init_mm,
|
|
|
|
};
|
|
|
|
|
2024-01-30 11:34:35 +01:00
|
|
|
bool ptdump_check_wx(void)
|
2016-10-27 09:27:34 -07:00
|
|
|
{
|
2024-09-09 12:47:18 +00:00
|
|
|
struct ptdump_pg_state st = {
|
2016-10-27 09:27:34 -07:00
|
|
|
.seq = NULL,
|
|
|
|
.marker = (struct addr_marker[]) {
|
|
|
|
{ 0, NULL},
|
|
|
|
{ -1, NULL},
|
|
|
|
},
|
2024-09-09 12:47:19 +00:00
|
|
|
.pg_level = &kernel_pg_levels[0],
|
2020-02-03 17:36:38 -08:00
|
|
|
.level = -1,
|
2016-10-27 09:27:34 -07:00
|
|
|
.check_wx = true,
|
2020-02-03 17:36:29 -08:00
|
|
|
.ptdump = {
|
|
|
|
.note_page = note_page,
|
|
|
|
.range = (struct ptdump_range[]) {
|
2024-02-14 13:29:23 +01:00
|
|
|
{_PAGE_OFFSET(vabits_actual), ~0UL},
|
2020-02-03 17:36:29 -08:00
|
|
|
{0, 0}
|
|
|
|
}
|
|
|
|
}
|
2016-10-27 09:27:34 -07:00
|
|
|
};
|
|
|
|
|
2020-02-03 17:36:42 -08:00
|
|
|
ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
|
2020-02-03 17:36:29 -08:00
|
|
|
|
2024-01-30 11:34:35 +01:00
|
|
|
if (st.wx_pages || st.uxn_pages) {
|
2016-10-27 09:27:34 -07:00
|
|
|
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
|
|
|
|
st.wx_pages, st.uxn_pages);
|
2024-01-30 11:34:35 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
} else {
|
2016-10-27 09:27:34 -07:00
|
|
|
pr_info("Checked W+X mappings: passed, no W+X pages found\n");
|
2024-01-30 11:34:35 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2016-10-27 09:27:34 -07:00
|
|
|
}
|
|
|
|
|
2021-03-30 13:54:49 +08:00
|
|
|
static int __init ptdump_init(void)
|
2016-05-31 14:49:01 +01:00
|
|
|
{
|
2023-12-13 09:40:29 +01:00
|
|
|
u64 page_offset = _PAGE_OFFSET(vabits_actual);
|
|
|
|
u64 vmemmap_start = (u64)virt_to_page((void *)page_offset);
|
2023-12-13 09:40:28 +01:00
|
|
|
struct addr_marker m[] = {
|
|
|
|
{ PAGE_OFFSET, "Linear Mapping start" },
|
|
|
|
{ PAGE_END, "Linear Mapping end" },
|
2020-12-22 12:02:06 -08:00
|
|
|
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
|
2023-12-13 09:40:28 +01:00
|
|
|
{ KASAN_SHADOW_START, "Kasan shadow start" },
|
|
|
|
{ KASAN_SHADOW_END, "Kasan shadow end" },
|
2019-08-07 16:55:16 +01:00
|
|
|
#endif
|
2023-12-13 09:40:28 +01:00
|
|
|
{ MODULES_VADDR, "Modules start" },
|
|
|
|
{ MODULES_END, "Modules end" },
|
|
|
|
{ VMALLOC_START, "vmalloc() area" },
|
|
|
|
{ VMALLOC_END, "vmalloc() end" },
|
2023-12-13 09:40:29 +01:00
|
|
|
{ vmemmap_start, "vmemmap start" },
|
2023-12-13 09:40:28 +01:00
|
|
|
{ VMEMMAP_END, "vmemmap end" },
|
|
|
|
{ PCI_IO_START, "PCI I/O start" },
|
|
|
|
{ PCI_IO_END, "PCI I/O end" },
|
|
|
|
{ FIXADDR_TOT_START, "Fixmap start" },
|
|
|
|
{ FIXADDR_TOP, "Fixmap end" },
|
|
|
|
{ -1, NULL },
|
|
|
|
};
|
|
|
|
static struct addr_marker address_markers[ARRAY_SIZE(m)] __ro_after_init;
|
|
|
|
|
|
|
|
kernel_ptdump_info.markers = memcpy(address_markers, m, sizeof(m));
|
2024-02-14 13:29:23 +01:00
|
|
|
kernel_ptdump_info.base_addr = page_offset;
|
2023-12-13 09:40:28 +01:00
|
|
|
|
2016-10-27 09:27:31 -07:00
|
|
|
ptdump_initialize();
|
2019-01-22 15:41:11 +01:00
|
|
|
ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
|
|
|
|
return 0;
|
2016-05-31 14:49:01 +01:00
|
|
|
}
|
2014-11-26 00:28:39 +00:00
|
|
|
device_initcall(ptdump_init);
|