summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Ostrovsky <boris.ostrovsky@oracle.com>2015-11-05 13:56:35 -0500
committerThomas Gleixner <tglx@linutronix.de>2015-11-07 10:39:39 +0100
commitf4e342c87776884f0309942a3880ca7e835239f9 (patch)
tree9406165675c8569eb732aa4f9446c9e94a1e8c8a
parent3849e91f571dcb48cf2c8143480c59137d44d6bc (diff)
downloadlinux-stable-f4e342c87776884f0309942a3880ca7e835239f9.tar.gz
linux-stable-f4e342c87776884f0309942a3880ca7e835239f9.tar.bz2
linux-stable-f4e342c87776884f0309942a3880ca7e835239f9.zip
x86/mm: Skip the hypervisor range when walking PGD
The range between 0xffff800000000000 and 0xffff87ffffffffff is reserved for hypervisor and therefore we should not try to follow PGD's indexes corresponding to those addresses. While this has always been a problem, with the new W+X warning mechanism ptdump_walk_pgd_level_core() can now be called during boot, causing a PV Xen guest to crash. [ tglx: Replaced the macro with a readable inline ] Fixes: e1a58320a38d "x86/mm: Warn on W^X mappings" Reported-by: Sander Eikelenboom <linux@eikelenboom.it> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: xen-devel@lists.xen.org Link: http://lkml.kernel.org/r/1446749795-27764-1-git-send-email-boris.ostrovsky@oracle.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/mm/dump_pagetables.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 1bf417e9cc13..a035c2aa7801 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -358,6 +358,21 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
#define pgd_none(a) pud_none(__pud(pgd_val(a)))
#endif
+#ifdef CONFIG_X86_64
+static inline bool is_hypervisor_range(int idx)
+{
+ /*
+ * ffff800000000000 - ffff87ffffffffff is reserved for
+ * the hypervisor.
+ */
+ return paravirt_enabled() &&
+ (idx >= pgd_index(__PAGE_OFFSET) - 16) &&
+ (idx < pgd_index(__PAGE_OFFSET));
+}
+#else
+static inline bool is_hypervisor_range(int idx) { return false; }
+#endif
+
static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
bool checkwx)
{
@@ -381,7 +396,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
for (i = 0; i < PTRS_PER_PGD; i++) {
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
- if (!pgd_none(*start)) {
+ if (!pgd_none(*start) && !is_hypervisor_range(i)) {
if (pgd_large(*start) || !pgd_present(*start)) {
prot = pgd_flags(*start);
note_page(m, &st, __pgprot(prot), 1);