From 8a3e058bbd075a599e6c268dbdf820ed48746bd1 Mon Sep 17 00:00:00 2001 From: maxv Date: Fri, 16 Dec 2016 19:52:22 +0000 Subject: [PATCH] The way the xen dummy page is taken care of makes absolutely no sense at all, with magic offsets here and there in different layers of the system. It is just blind luck that everything has always worked as expected so far. Due to this wrong design we have a problem now: we allocate one physical page for lapic, and it happens to overlap with the dummy page, which causes the system to crash. Fix this by keeping the dummy va directly in a variable instead of magic offsets. The asm locore now increments the first pa to hide the dummy page to machdep and pmap. --- sys/arch/amd64/amd64/locore.S | 6 +++--- sys/arch/i386/i386/locore.S | 8 ++++---- sys/arch/i386/i386/machdep.c | 10 +++++----- sys/arch/x86/x86/pmap.c | 9 +++++---- sys/arch/xen/x86/x86_xpmap.c | 25 +++++++++++++++++++++---- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index a49bd46d6876..2e545971820c 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.116 2016/12/09 17:57:24 maxv Exp $ */ +/* $NetBSD: locore.S,v 1.117 2016/12/16 19:52:22 maxv Exp $ */ /* * Copyright-o-rama! @@ -948,9 +948,9 @@ longmode_hi: movw %ax,%gs movw %ax,%fs - /* Set first_avail after the UAREA. */ + /* Set first_avail after the DUMMY PAGE (see xen_locore). */ movq %rsi,%rdi - addq $USPACE,%rdi + addq $(USPACE+PAGE_SIZE),%rdi subq $KERNBASE,%rdi /* init_x86_64 wants a physical address */ #endif /* XEN */ diff --git a/sys/arch/i386/i386/locore.S b/sys/arch/i386/i386/locore.S index 29d9a8f6db63..edba305ddd98 100644 --- a/sys/arch/i386/i386/locore.S +++ b/sys/arch/i386/i386/locore.S @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.142 2016/12/06 15:05:07 maxv Exp $ */ +/* $NetBSD: locore.S,v 1.143 2016/12/16 19:52:22 maxv Exp $ */ /* * Copyright-o-rama! @@ -128,7 +128,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.142 2016/12/06 15:05:07 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.143 2016/12/16 19:52:22 maxv Exp $"); #include "opt_compat_oldboot.h" #include "opt_copy_symtab.h" @@ -918,8 +918,8 @@ begin: leal (USPACE-FRAMESIZE)(%eax),%esp xorl %ebp,%ebp /* mark end of frames */ - /* Set first_avail after the UAREA. */ - addl $USPACE,%esi + /* Set first_avail after the DUMMY PAGE (see xen_locore). */ + addl $(USPACE+PAGE_SIZE),%esi subl $KERNBASE,%esi /* init386 wants a physical address */ #ifdef PAE diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 0c33678cfbd1..dc5251e775d2 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.767 2016/12/15 12:04:18 kamil Exp $ */ +/* $NetBSD: machdep.c,v 1.768 2016/12/16 19:52:22 maxv Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009 @@ -67,7 +67,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.767 2016/12/15 12:04:18 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.768 2016/12/16 19:52:22 maxv Exp $"); #include "opt_beep.h" #include "opt_compat_ibcs2.h" @@ -1214,9 +1214,9 @@ init386(paddr_t first_avail) /* Parse Xen command line (replace bootinfo) */ xen_parse_cmdline(XEN_PARSE_BOOTFLAGS, NULL); - /* Steal one page for gdt */ - gdt = (void *)((u_long)first_avail + KERNBASE); - first_avail += PAGE_SIZE; + /* Use the dummy page as a gdt */ + extern vaddr_t xen_dummy_page; + gdt = (void *)xen_dummy_page; /* Determine physical address space */ first_avail = round_page(first_avail); diff --git a/sys/arch/x86/x86/pmap.c b/sys/arch/x86/x86/pmap.c index 2f8fef73db7f..f0fdd17f53a3 100644 --- a/sys/arch/x86/x86/pmap.c +++ b/sys/arch/x86/x86/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.231 2016/12/13 10:54:27 kamil Exp $ */ +/* $NetBSD: pmap.c,v 1.232 2016/12/16 19:52:22 maxv Exp $ */ /*- * Copyright (c) 2008, 2010, 2016 The NetBSD Foundation, Inc. @@ -171,7 +171,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.231 2016/12/13 10:54:27 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.232 2016/12/16 19:52:22 maxv Exp $"); #include "opt_user_ldt.h" #include "opt_lockdebug.h" @@ -1399,15 +1399,16 @@ pmap_bootstrap(vaddr_t kva_start) #endif #if defined(XEN) && defined(__x86_64__) + extern vaddr_t xen_dummy_page; /* * We want a dummy page directory for Xen: when deactivating a pmap, Xen * will still consider it active. So we set user PGD to this one to lift * all protection on the now inactive page tables set. */ - xen_dummy_user_pgd = pmap_bootstrap_palloc(1); + xen_dummy_user_pgd = xen_dummy_page - KERNBASE; /* Zero fill it, the less checks in Xen it requires the better */ - memset((void *) (xen_dummy_user_pgd + KERNBASE), 0, PAGE_SIZE); + memset((void *)(xen_dummy_user_pgd + KERNBASE), 0, PAGE_SIZE); /* Mark read-only */ HYPERVISOR_update_va_mapping(xen_dummy_user_pgd + KERNBASE, pmap_pa2pte(xen_dummy_user_pgd) | PG_u | PG_V, UVMF_INVLPG); diff --git a/sys/arch/xen/x86/x86_xpmap.c b/sys/arch/xen/x86/x86_xpmap.c index dc32ddd4f542..6d17fdf0d35a 100644 --- a/sys/arch/xen/x86/x86_xpmap.c +++ b/sys/arch/xen/x86/x86_xpmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: x86_xpmap.c,v 1.67 2016/11/15 17:01:12 maxv Exp $ */ +/* $NetBSD: x86_xpmap.c,v 1.68 2016/12/16 19:52:22 maxv Exp $ */ /* * Copyright (c) 2006 Mathieu Ropert @@ -66,7 +66,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.67 2016/11/15 17:01:12 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.68 2016/12/16 19:52:22 maxv Exp $"); #include "opt_xen.h" #include "opt_ddb.h" @@ -103,6 +103,7 @@ volatile shared_info_t *HYPERVISOR_shared_info; union start_info_union start_info_union __aligned(PAGE_SIZE); unsigned long *xpmap_phys_to_machine_mapping; kmutex_t pte_lock; +vaddr_t xen_dummy_page; void xen_failsafe_handler(void); @@ -588,6 +589,20 @@ static const int l2_4_count = PTP_LEVELS - 1; /* * Xen locore: get rid of the Xen bootstrap tables. Build and switch to new page * tables. + * + * Virtual address space of the kernel when leaving this function: + * +--------------+------------------+-------------+------------+--------------- + * | KERNEL IMAGE | BOOTSTRAP TABLES | PROC0 UAREA | DUMMY PAGE | HYPER. SHARED + * +--------------+------------------+-------------+------------+--------------- + * + * ------+-----------------+-------------+ + * INFO | EARLY ZERO PAGE | ISA I/O MEM | + * ------+-----------------+-------------+ + * + * DUMMY PAGE is either a PDG for amd64 or a GDT for i386. + * + * (HYPER. SHARED INFO + EARLY ZERO PAGE + ISA I/O MEM) have no physical + * addresses preallocated. */ vaddr_t xen_locore(void) @@ -694,7 +709,7 @@ bootstrap_again: xen_bootstrap_tables(bootstrap_tables, init_tables, oldcount + l2_4_count, count, true); - /* Zero out free space after tables */ + /* Zero out PROC0 UAREA and DUMMY PAGE. */ memset((void *)(init_tables + ((count + l2_4_count) * PAGE_SIZE)), 0, (UPAGES + 1) * PAGE_SIZE); @@ -746,7 +761,9 @@ xen_bootstrap_tables(vaddr_t old_pgd, vaddr_t new_pgd, size_t old_count, */ map_end = new_pgd + ((new_count + l2_4_count) * PAGE_SIZE); if (final) { - map_end += (UPAGES + 1) * PAGE_SIZE; + map_end += UPAGES * PAGE_SIZE; + xen_dummy_page = (vaddr_t)map_end; + map_end += PAGE_SIZE; HYPERVISOR_shared_info = (shared_info_t *)map_end; map_end += PAGE_SIZE; early_zerop = (char *)map_end;