diff --git a/sys/arch/xen/include/xenpmap.h b/sys/arch/xen/include/xenpmap.h index 6edae0397108..367766a0a1da 100644 --- a/sys/arch/xen/include/xenpmap.h +++ b/sys/arch/xen/include/xenpmap.h @@ -1,4 +1,4 @@ -/* $NetBSD: xenpmap.h,v 1.27 2011/04/29 22:45:41 jym Exp $ */ +/* $NetBSD: xenpmap.h,v 1.28 2011/08/10 09:50:37 cherry Exp $ */ /* * @@ -36,6 +36,8 @@ #define INVALID_P2M_ENTRY (~0UL) +void xpq_queue_lock(void); +void xpq_queue_unlock(void); void xpq_queue_machphys_update(paddr_t, paddr_t); void xpq_queue_invlpg(vaddr_t); void xpq_queue_pte_update(paddr_t, pt_entry_t); @@ -46,6 +48,13 @@ void xpq_queue_tlb_flush(void); void xpq_queue_pin_table(paddr_t, int); void xpq_queue_unpin_table(paddr_t); int xpq_update_foreign(paddr_t, pt_entry_t, int); +void xen_vcpu_mcast_invlpg(vaddr_t, vaddr_t, uint32_t); +void xen_vcpu_bcast_invlpg(vaddr_t, vaddr_t); +void xen_mcast_tlbflush(uint32_t); +void xen_bcast_tlbflush(void); +void xen_mcast_invlpg(vaddr_t, uint32_t); +void xen_bcast_invlpg(vaddr_t); + #define xpq_queue_pin_l1_table(pa) \ xpq_queue_pin_table(pa, MMUEXT_PIN_L1_TABLE) diff --git a/sys/arch/xen/x86/x86_xpmap.c b/sys/arch/xen/x86/x86_xpmap.c index 640df3cb60ef..b24ce88290ba 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.28 2011/06/15 20:50:02 rmind Exp $ */ +/* $NetBSD: x86_xpmap.c,v 1.29 2011/08/10 09:50:37 cherry Exp $ */ /* * Copyright (c) 2006 Mathieu Ropert @@ -69,7 +69,7 @@ #include -__KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.28 2011/06/15 20:50:02 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.29 2011/08/10 09:50:37 cherry Exp $"); #include "opt_xen.h" #include "opt_ddb.h" @@ -77,6 +77,7 @@ __KERNEL_RCSID(0, "$NetBSD: x86_xpmap.c,v 1.28 2011/06/15 20:50:02 rmind Exp $") #include #include +#include #include @@ -152,7 +153,9 @@ xen_set_ldt(vaddr_t base, uint32_t entries) pmap_pte_clearbits(ptp, PG_RW); } s = splvm(); + xpq_queue_lock(); xpq_queue_set_ldt(base, entries); + xpq_queue_unlock(); splx(s); } @@ -163,12 +166,27 @@ void xpq_debug_dump(void); #define XPQUEUE_SIZE 2048 static mmu_update_t xpq_queue[XPQUEUE_SIZE]; static int xpq_idx = 0; +static struct simplelock xpq_lock = SIMPLELOCK_INITIALIZER; +void +xpq_queue_lock(void) +{ + simple_lock(&xpq_lock); +} + +void +xpq_queue_unlock(void) +{ + simple_unlock(&xpq_lock); +} + +/* Must be called with xpq_lock held */ void xpq_flush_queue(void) { int i, ok, ret; + KASSERT(simple_lock_held(&xpq_lock)); XENPRINTK2(("flush queue %p entries %d\n", xpq_queue, xpq_idx)); for (i = 0; i < xpq_idx; i++) XENPRINTK2(("%d: 0x%08" PRIx64 " 0x%08" PRIx64 "\n", i, @@ -187,10 +205,12 @@ xpq_flush_queue(void) xpq_idx = 0; } +/* Must be called with xpq_lock held */ static inline void xpq_increment_idx(void) { + KASSERT(simple_lock_held(&xpq_lock)); xpq_idx++; if (__predict_false(xpq_idx == XPQUEUE_SIZE)) xpq_flush_queue(); @@ -201,6 +221,7 @@ xpq_queue_machphys_update(paddr_t ma, paddr_t pa) { XENPRINTK2(("xpq_queue_machphys_update ma=0x%" PRIx64 " pa=0x%" PRIx64 "\n", (int64_t)ma, (int64_t)pa)); + KASSERT(simple_lock_held(&xpq_lock)); xpq_queue[xpq_idx].ptr = ma | MMU_MACHPHYS_UPDATE; xpq_queue[xpq_idx].val = (pa - XPMAP_OFFSET) >> PAGE_SHIFT; xpq_increment_idx(); @@ -214,6 +235,7 @@ xpq_queue_pte_update(paddr_t ptr, pt_entry_t val) { KASSERT((ptr & 3) == 0); + KASSERT(simple_lock_held(&xpq_lock)); xpq_queue[xpq_idx].ptr = (paddr_t)ptr | MMU_NORMAL_PT_UPDATE; xpq_queue[xpq_idx].val = val; xpq_increment_idx(); @@ -226,6 +248,7 @@ void xpq_queue_pt_switch(paddr_t pa) { struct mmuext_op op; + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_pt_switch: 0x%" PRIx64 " 0x%" PRIx64 "\n", @@ -240,6 +263,8 @@ void xpq_queue_pin_table(paddr_t pa, int lvl) { struct mmuext_op op; + + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_pin_l%d_table: %#" PRIxPADDR "\n", @@ -256,6 +281,8 @@ void xpq_queue_unpin_table(paddr_t pa) { struct mmuext_op op; + + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_unpin_table: %#" PRIxPADDR "\n", pa)); @@ -269,6 +296,8 @@ void xpq_queue_set_ldt(vaddr_t va, uint32_t entries) { struct mmuext_op op; + + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_set_ldt\n")); @@ -284,6 +313,8 @@ void xpq_queue_tlb_flush(void) { struct mmuext_op op; + + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_tlb_flush\n")); @@ -296,20 +327,25 @@ void xpq_flush_cache(void) { struct mmuext_op op; - int s = splvm(); + int s = splvm(), err; + + xpq_queue_lock(); xpq_flush_queue(); XENPRINTK2(("xpq_queue_flush_cache\n")); op.cmd = MMUEXT_FLUSH_CACHE; - if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) + if ((err = HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) < 0) + printf("errno == %d\n", err); panic("xpq_flush_cache"); - splx(s); + xpq_queue_unlock(); + splx(s); /* XXX: removeme */ } void xpq_queue_invlpg(vaddr_t va) { struct mmuext_op op; + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); XENPRINTK2(("xpq_queue_invlpg %#" PRIxVADDR "\n", va)); @@ -319,11 +355,134 @@ xpq_queue_invlpg(vaddr_t va) panic("xpq_queue_invlpg"); } +void +xen_mcast_invlpg(vaddr_t va, uint32_t cpumask) +{ + mmuext_op_t op; + + KASSERT(simple_lock_held(&xpq_lock)); + + /* Flush pending page updates */ + xpq_flush_queue(); + + op.cmd = MMUEXT_INVLPG_MULTI; + op.arg1.linear_addr = va; + op.arg2.vcpumask = &cpumask; + + if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { + panic("xpq_queue_invlpg_all"); + } + + return; +} + +void +xen_bcast_invlpg(vaddr_t va) +{ + mmuext_op_t op; + + /* Flush pending page updates */ + KASSERT(simple_lock_held(&xpq_lock)); + xpq_flush_queue(); + + op.cmd = MMUEXT_INVLPG_ALL; + op.arg1.linear_addr = va; + + if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { + panic("xpq_queue_invlpg_all"); + } + + return; +} + +/* This is a synchronous call. */ +void +xen_mcast_tlbflush(uint32_t cpumask) +{ + mmuext_op_t op; + + /* Flush pending page updates */ + KASSERT(simple_lock_held(&xpq_lock)); + xpq_flush_queue(); + + op.cmd = MMUEXT_TLB_FLUSH_MULTI; + op.arg2.vcpumask = &cpumask; + + if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { + panic("xpq_queue_invlpg_all"); + } + + return; +} + +/* This is a synchronous call. */ +void +xen_bcast_tlbflush(void) +{ + mmuext_op_t op; + + /* Flush pending page updates */ + KASSERT(simple_lock_held(&xpq_lock)); + xpq_flush_queue(); + + op.cmd = MMUEXT_TLB_FLUSH_ALL; + + if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) { + panic("xpq_queue_invlpg_all"); + } + + return; +} + +/* This is a synchronous call. */ +void +xen_vcpu_mcast_invlpg(vaddr_t sva, vaddr_t eva, uint32_t cpumask) +{ + KASSERT(eva > sva); + + /* Flush pending page updates */ + KASSERT(simple_lock_held(&xpq_lock)); + xpq_flush_queue(); + + /* Align to nearest page boundary */ + sva &= ~PAGE_MASK; + eva &= ~PAGE_MASK; + + for ( ; sva <= eva; sva += PAGE_SIZE) { + xen_mcast_invlpg(sva, cpumask); + } + + return; +} + +/* This is a synchronous call. */ +void +xen_vcpu_bcast_invlpg(vaddr_t sva, vaddr_t eva) +{ + KASSERT(eva > sva); + + /* Flush pending page updates */ + KASSERT(simple_lock_held(&xpq_lock)); + xpq_flush_queue(); + + /* Align to nearest page boundary */ + sva &= ~PAGE_MASK; + eva &= ~PAGE_MASK; + + for ( ; sva <= eva; sva += PAGE_SIZE) { + xen_bcast_invlpg(sva); + } + + return; +} + int xpq_update_foreign(paddr_t ptr, pt_entry_t val, int dom) { mmu_update_t op; int ok; + + KASSERT(simple_lock_held(&xpq_lock)); xpq_flush_queue(); op.ptr = ptr;