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.
This commit is contained in:
maxv 2016-12-16 19:52:22 +00:00
parent e5909f155b
commit 8a3e058bbd
5 changed files with 38 additions and 20 deletions

View File

@ -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 */

View File

@ -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 <machine/asm.h>
__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

View File

@ -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 <sys/cdefs.h>
__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);

View File

@ -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 <sys/cdefs.h>
__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);

View File

@ -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 <mro@adviseo.fr>
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__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;