[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC][PATCH 02/13] Kemari: core kemari code
This is an updated version of the following patch. No major changes. http://lists.xensource.com/archives/html/xen-devel/2009-03/msg00373.html Signed-off-by: Yoshi Tamura <tamura.yoshiaki@xxxxxxxxxxxxx> Signed-off-by: Yoshisato Yanagisawa <yanagisawa.yoshisato@xxxxxxxxxxxxx> --- xen/arch/x86/Makefile | 1 xen/arch/x86/domain.c | 4 xen/arch/x86/domctl.c | 16 xen/arch/x86/kemari/Makefile | 1 xen/arch/x86/kemari/kemari.c | 670 +++++++++++++++++++++++++++++++++++++++++ xen/include/public/domctl.h | 33 ++ xen/include/public/io/xenbus.h | 4 xen/include/public/kemari.h | 97 +++++ xen/include/xen/kemari.h | 75 ++++ 9 files changed, 900 insertions(+), 1 deletion(-) diff -r b249f3e979a5 -r cf6a910e3663 xen/include/public/kemari.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/kemari.h Wed Mar 11 18:03:47 2009 +0900 @@ -0,0 +1,97 @@ +/****************************************************************************** + * kemari.h + * + * Tools interface to Kemari. + * + * Copyright (c) 2008 Nippon Telegraph and Telephone Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __XEN_PUBLIC_KEMARI_H__ +#define __XEN_PUBLIC_KEMARI_H__ + +#define KEMARI_TAP_OFF 0 +#define KEMARI_TAP_IN 1 +#define KEMARI_TAP_OUT 2 + +struct kemari_ring { + uint32_t cons; + uint32_t prod; + uint32_t num_ents; + unsigned int dirty_bitmap_size; /* num of ditry bits */ + struct { + uint32_t buf_size; + uint32_t rec_size; + uint32_t buf_offset; + } hvm_ctxt; + char data[1]; +}; + +struct kemari_ent { + union { + struct { + uint16_t pages; + uint16_t port; + } header; + struct { + uint16_t start; + uint16_t end; + } index; + unsigned long dirty_bitmap; + } u; +}; + +#define KEMARI_RING_GET_PROD(_ring) \ + (&((struct kemari_ent *)(_ring)->data)[(_ring)->prod % (_ring)->num_ents]) + +#define KEMARI_RING_GET_CONS(_ring) \ + (&((struct kemari_ent *)(_ring)->data)[(_ring)->cons % (_ring)->num_ents]) + +static inline void kemari_ring_read(struct kemari_ring *ring, + struct kemari_ent **buf) +{ + *buf = KEMARI_RING_GET_CONS(ring); +#ifdef __XEN__ + wmb(); +#elif __XEN_TOOLS__ + xen_wmb(); +#endif + ring->cons++; +} + +static inline void kemari_ring_write(struct kemari_ring *ring, + struct kemari_ent *buf) +{ + memcpy(KEMARI_RING_GET_PROD(ring), buf, sizeof(struct kemari_ent)); +#ifdef __XEN__ + wmb(); +#elif __XEN_TOOLS__ + xen_wmb(); +#endif + ring->prod++; +} + +#endif /* __XEN_PUBLIC_KEMARI_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r b249f3e979a5 -r cf6a910e3663 xen/include/public/domctl.h --- a/xen/include/public/domctl.h Mon Mar 09 10:32:24 2009 +0000 +++ b/xen/include/public/domctl.h Wed Mar 11 18:03:47 2009 +0900 @@ -645,6 +645,38 @@ } xen_domctl_hvmcontext_partial_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_partial_t); +/* Kemari interface */ +#define XEN_DOMCTL_kemari_op 56 + +#define _XEN_KEMARI_OP_enable 0 +#define XEN_KEMARI_OP_enable (1UL<<_XEN_KEMARI_OP_enable) +#define _XEN_KEMARI_OP_off 1 +#define XEN_KEMARI_OP_off (1UL<<_XEN_KEMARI_OP_off) +#define _XEN_KEMARI_OP_attach 2 +#define XEN_KEMARI_OP_attach (1UL<<_XEN_KEMARI_OP_attach) +#define _XEN_KEMARI_OP_detach 3 +#define XEN_KEMARI_OP_detach (1UL<<_XEN_KEMARI_OP_detach) + +struct xen_domctl_kemari_op { + uint32_t cmd; + + union { + struct { + uint32_t port; + uint32_t num_pages; + uint64_t mfn; + } enable; /* XEN_KEMARI_OP_enable */ + struct { + uint32_t port; + uint16_t evtchn_tap_mode; + } attach; /* XEN_KEMARI_OP_attach */ + struct { + uint32_t port; + } detach; /* XEN_KEMARI_OP_detach */ + } u; +}; +typedef struct xen_domctl_kemari_op xen_domctl_kemari_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_kemari_op_t); struct xen_domctl { uint32_t cmd; @@ -687,6 +719,7 @@ struct xen_domctl_set_target set_target; struct xen_domctl_subscribe subscribe; struct xen_domctl_debug_op debug_op; + struct xen_domctl_kemari_op kemari_op; #if defined(__i386__) || defined(__x86_64__) struct xen_domctl_cpuid cpuid; #endif diff -r b249f3e979a5 -r cf6a910e3663 xen/include/public/io/xenbus.h --- a/xen/include/public/io/xenbus.h Mon Mar 09 10:32:24 2009 +0000 +++ b/xen/include/public/io/xenbus.h Wed Mar 11 18:03:47 2009 +0900 @@ -63,7 +63,9 @@ */ XenbusStateReconfiguring = 7, - XenbusStateReconfigured = 8 + XenbusStateReconfigured = 8, + + XenbusStateAttached = 9 }; typedef enum xenbus_state XenbusState; diff -r b249f3e979a5 -r cf6a910e3663 xen/include/xen/kemari.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/xen/kemari.h Wed Mar 11 18:03:47 2009 +0900 @@ -0,0 +1,75 @@ +/****************************************************************************** + * kemari.h + * + * Kemari header file. + * + * Copyright (C) 2008 Nippon Telegraph and Telephone Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __XEN_KEMARI_H__ +#define __XEN_KEMARI_H__ + +#include <public/domctl.h> + +#define NUM_KEMARI_TAPS 32 + +#define _KEMARI_TAP_ATTACHED 0 +#define KEMARI_TAP_ATTACHED (1UL<<_KEMARI_TAP_ATTACHED) +#define _KEMARI_TAP_DETACHED 1 +#define KEMARI_TAP_DETACHED (1UL<<_KEMARI_TAP_DETACHED) + +struct kemari_tap { + uint64_t status; + uint64_t in_events; + uint64_t out_events; +}; + +/* Main data structure of Kemari */ +struct kemari { + struct domain *domain; + + struct kemari_ring *ring; + + uint32_t port; + + uint32_t num_pages; + + uint64_t mfn; + + uint64_t num_events; + + uint64_t priv_dirty_pages; + + struct kemari_tap taps[NUM_KEMARI_TAPS]; +}; + +long kemari_off(struct domain *d); + +/* Entry point to Kemari */ +long do_kemari_op(struct domain *d, struct xen_domctl_kemari_op *kemari_op); + +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r b249f3e979a5 -r cf6a910e3663 xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile Mon Mar 09 10:32:24 2009 +0000 +++ b/xen/arch/x86/Makefile Wed Mar 11 18:03:47 2009 +0900 @@ -4,6 +4,7 @@ subdir-y += hvm subdir-y += mm subdir-y += oprofile +subdir-y += kemari subdir-$(x86_32) += x86_32 subdir-$(x86_64) += x86_64 diff -r b249f3e979a5 -r cf6a910e3663 xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Mon Mar 09 10:32:24 2009 +0000 +++ b/xen/arch/x86/domain.c Wed Mar 11 18:03:47 2009 +0900 @@ -1912,6 +1912,10 @@ BUG(); } + /* Turn off Kemari. */ + if ( d->kemari ) + kemari_off(d); + if ( is_hvm_domain(d) ) hvm_domain_relinquish_resources(d); diff -r b249f3e979a5 -r cf6a910e3663 xen/arch/x86/domctl.c --- a/xen/arch/x86/domctl.c Mon Mar 09 10:32:24 2009 +0000 +++ b/xen/arch/x86/domctl.c Wed Mar 11 18:03:47 2009 +0900 @@ -20,6 +20,7 @@ #include <xen/trace.h> #include <xen/console.h> #include <xen/iocap.h> +#include <xen/kemari.h> #include <xen/paging.h> #include <asm/irq.h> #include <asm/hvm/hvm.h> @@ -1079,6 +1080,21 @@ } break; + case XEN_DOMCTL_kemari_op: + { + struct domain *d = rcu_lock_domain_by_id(domctl->domain); + + ret = -ESRCH; + if ( unlikely(d == NULL) ) + break; + + ret = do_kemari_op(d, &domctl->u.kemari_op); + + copy_to_guest(u_domctl, domctl, 1); + rcu_unlock_domain(d); + } + break; + default: ret = -ENOSYS; break; diff -r b249f3e979a5 -r cf6a910e3663 xen/arch/x86/kemari/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/kemari/Makefile Wed Mar 11 18:03:47 2009 +0900 @@ -0,0 +1,1 @@ +obj-y += kemari.o diff -r b249f3e979a5 -r cf6a910e3663 xen/arch/x86/kemari/kemari.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/kemari/kemari.c Wed Mar 11 18:03:47 2009 +0900 @@ -0,0 +1,670 @@ +/****************************************************************************** + * kemari.c + * + * The hypervisor part of VM synchronization mechanism (Kemari). + * + * Copyright (c) 2008 Nippon Telegraph and Telephone Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copied log_dirty_lock(_d), log_dirty_unlock(_d) and paging_log_dirty_op() + * from arch/x86/paging.c. + * + * x86 specific paging support + * Copyright (c) 2007 Advanced Micro Devices (Wei Huang) + * Copyright (c) 2007 XenSource Inc. + */ + +#include <xen/config.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/event.h> +#include <xen/kemari.h> +#include <xen/mm.h> +#include <xen/domain.h> + +#include <public/kemari.h> +#include <asm/domain.h> +#include <asm/hvm/support.h> +#include <asm/page.h> +#include <asm/paging.h> +#include <asm/shadow.h> +#include <asm/types.h> + +/* Override macros from asm/page.h to make them work with mfn_t */ +#undef mfn_valid +#define mfn_valid(_mfn) __mfn_valid(mfn_x(_mfn)) + +#define log_dirty_lock(_d) \ + do { \ + if (unlikely((_d)->arch.paging.log_dirty.locker==current->processor))\ + { \ + printk("Error: paging log dirty lock held by %s\n", \ + (_d)->arch.paging.log_dirty.locker_function); \ + BUG(); \ + } \ + spin_lock(&(_d)->arch.paging.log_dirty.lock); \ + ASSERT((_d)->arch.paging.log_dirty.locker == -1); \ + (_d)->arch.paging.log_dirty.locker = current->processor; \ + (_d)->arch.paging.log_dirty.locker_function = __func__; \ + } while (0) + +#define log_dirty_unlock(_d) \ + do { \ + ASSERT((_d)->arch.paging.log_dirty.locker == current->processor); \ + (_d)->arch.paging.log_dirty.locker = -1; \ + (_d)->arch.paging.log_dirty.locker_function = "nobody"; \ + spin_unlock(&(_d)->arch.paging.log_dirty.lock); \ + } while (0) + +#define bucket_from_port(d,p) \ + ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET]) +#define port_is_valid(d,p) \ + (((p) >= 0) && ((p) < MAX_EVTCHNS(d)) && \ + (bucket_from_port(d,p) != NULL)) +#define evtchn_from_port(d,p) \ + (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)]) + +static void kemari_send_domaininfo_ctxt(struct kemari_ring *ring, + struct domain *d) +{ + struct hvm_domain_context ctxt; + + if ( !d->is_paused_by_controller ) + { + dprintk(XENLOG_ERR, "Domain isn't paused\n"); + return; + } + + ctxt.cur = 0; + ctxt.size = ring->hvm_ctxt.buf_size; + ctxt.data = (uint8_t *)ring + ring->hvm_ctxt.buf_offset; + hvm_save(d, &ctxt); + ring->hvm_ctxt.rec_size = ctxt.cur; +} + +static long kemari_send_dirty_bitmap_page(struct kemari_ring *ring, + struct domain *d, + unsigned long *dirty_bitmap, + uint16_t index, unsigned int bytes) +{ + uint16_t i, j; + struct kemari_ent *buf; + + for ( i = 0; i < bytes / BYTES_PER_LONG; i++ ) + { + j = i; + + while ( (j < bytes / BYTES_PER_LONG) && (dirty_bitmap[j] != 0) ) + j++; + + if ( i == j ) + continue; + + buf = KEMARI_RING_GET_PROD(ring); + buf->u.index.start = i + index; + buf->u.index.end = j + index; + wmb(); + ring->prod++; + + while( i < j ) + { + buf = (struct kemari_ent *)&dirty_bitmap[i]; + kemari_ring_write(ring, buf); + i++; + } + } + return i; +} + +/* Based on paging_log_dirty_op() in xen/arch/x86/mm/paging.c. */ +static long kemari_send_dirty_bitmap(struct kemari_ring *ring, + struct domain *d) +{ + long ret = 0, clean = 1, peek = 1; + unsigned long pages = 0; + unsigned long p2m_size; + mfn_t *l4, *l3, *l2; + unsigned long *l1; + int i4, i3, i2; + uint16_t index = 0; + + log_dirty_lock(d); + + if ( clean ) + { + d->arch.paging.log_dirty.fault_count = 0; + d->arch.paging.log_dirty.dirty_count = 0; + } + + if ( !mfn_valid(d->arch.paging.log_dirty.top) ) + { + ret = -EINVAL; /* perhaps should be ENOMEM? */ + goto out; + } + + if ( unlikely(d->arch.paging.log_dirty.failed_allocs) ) { + printk("%s: %d failed page allocs while logging dirty pages\n", + __FUNCTION__, d->arch.paging.log_dirty.failed_allocs); + ret = -ENOMEM; + goto out; + } + + pages = 0; + l4 = map_domain_page(mfn_x(d->arch.paging.log_dirty.top)); + + p2m_size = domain_get_maximum_gpfn(d) + 1; + + for ( i4 = 0; + (pages < p2m_size) && (i4 < LOGDIRTY_NODE_ENTRIES); + i4++ ) + { + l3 = mfn_valid(l4[i4]) ? map_domain_page(mfn_x(l4[i4])) : NULL; + for ( i3 = 0; + (pages < p2m_size) && (i3 < LOGDIRTY_NODE_ENTRIES); + i3++ ) + { + l2 = ((l3 && mfn_valid(l3[i3])) ? + map_domain_page(mfn_x(l3[i3])) : NULL); + for ( i2 = 0; + (pages < p2m_size) && (i2 < LOGDIRTY_NODE_ENTRIES); + i2++ ) + { + unsigned int bytes = PAGE_SIZE; + l1 = ((l2 && mfn_valid(l2[i2])) ? + map_domain_page(mfn_x(l2[i2])) : NULL); + if ( unlikely(((p2m_size - pages + 7) >> 3) < bytes) ) + bytes = (unsigned int)((p2m_size - pages + + BITS_PER_LONG - 1) >> 3); + if ( likely(peek) ) + { + if ( l1 != NULL && + kemari_send_dirty_bitmap_page(ring, d, l1, + index, bytes) < 0 ) + { + ret = -EFAULT; + dprintk(XENLOG_ERR, + "%s: kemari_send_dirty_bitmap_page\n", + __FUNCTION__); + goto out; + } + } + index += PAGE_SIZE / BYTES_PER_LONG; + + if ( clean && l1 != NULL ) + clear_page(l1); + pages += bytes << 3; + if ( l1 != NULL ) + unmap_domain_page(l1); + } + if ( l2 ) + unmap_domain_page(l2); + } + if ( l3 ) + unmap_domain_page(l3); + } + unmap_domain_page(l4); + + log_dirty_unlock(d); + + if ( clean ) + { + /* We need to further call clean_dirty_bitmap() functions of specific + * paging modes (shadow or hap). Safe because the domain is paused. */ + d->arch.paging.log_dirty.clean_dirty_bitmap(d); + } + + return ret; + + out: + log_dirty_unlock(d); + + return ret; +} + +static void kemari_guest_notify(struct kemari *kemari) +{ + if ( likely(kemari != NULL) ) + notify_via_xen_evtchn_tap(kemari->domain, kemari->port); +} + +/* VM synchronization entry point. */ +static long run_kemari(struct evtchn *lchn, struct evtchn *rchn) +{ + long ret; + uint32_t port; + uint64_t *events; + struct domain *d, *rd = lchn->u.interdomain.remote_dom; + struct kemari *kemari; + struct kemari_ring *ring; + struct evtchn *kemari_evtchn; + + if (lchn->tap.mode & KEMARI_TAP_OUT) + { + domain_pause_for_debugger(); + d = current->domain; + kemari = d->kemari; + port = rchn->u.interdomain.remote_port; + events = &kemari->taps[port].out_events; + } + else if (rchn->tap.mode & KEMARI_TAP_IN) + { + domain_pause_by_systemcontroller(rd); + d = rd; + kemari = rd->kemari; + port = lchn->u.interdomain.remote_port; + events = &kemari->taps[port].in_events; + } + else + { + ret = 0; + goto out; + } + + spin_lock(&d->grant_table->lock); + + ++*events; + + kemari_evtchn = evtchn_from_port(d, kemari->port); + if (kemari_evtchn->notify_vcpu_id != current->vcpu_id) + kemari_evtchn->notify_vcpu_id = current->vcpu_id; + + ring = kemari->ring; + + ret = kemari_send_dirty_bitmap(ring, d); + if ( ret < 0 ) + goto unlock_out; + + kemari_guest_notify(kemari); + + prepare_wait_on_xen_event_channel(kemari->port); + + test_and_clear_bit(_VPF_blocked_in_xen, ¤t->pause_flags); + + ret = 0; + + unlock_out: + spin_unlock(&d->grant_table->lock); + + out: + return ret; +} + +static long kemari_bind_tap(struct domain *d, + struct xen_domctl_kemari_op *kemari_op) +{ + long ret; + struct evtchn_bind_tap bind_tap; + + bind_tap.tap_dom = d->domain_id; + bind_tap.tap_port = kemari_op->u.attach.port; + bind_tap.mode = kemari_op->u.attach.evtchn_tap_mode; + bind_tap.redirect = run_kemari; + + ret = evtchn_bind_tap(&bind_tap); + + return ret; +} + +static long kemari_unbind_tap(struct domain *d, + struct xen_domctl_kemari_op *kemari_op) +{ + long ret; + struct evtchn_bind_tap unbind_tap; + + unbind_tap.tap_dom = d->domain_id; + unbind_tap.tap_port = kemari_op->u.detach.port; + unbind_tap.mode = KEMARI_TAP_OFF; + + ret = evtchn_unbind_tap(&unbind_tap); + + return ret; +} + +static long kemari_attach(struct domain *d, + struct xen_domctl_kemari_op *kemari_op) +{ + long ret; + uint32_t port = kemari_op->u.attach.port; + struct kemari *kemari = d->kemari; + struct kemari_tap *tap; + + dprintk(XENLOG_DEBUG, "%s: in\n", __FUNCTION__); + + ret = -EINVAL; + if ( unlikely(kemari == NULL) ) + { + dprintk(XENLOG_ERR, "kemari is off\n"); + goto out; + } + dprintk(XENLOG_DEBUG, "%s: kemari_bind_tap\n", __FUNCTION__); + ret = kemari_bind_tap(d, kemari_op); + if (ret < 0) + { + dprintk(XENLOG_ERR, + "couldn't bind evtchn tap port=%u\n", port); + goto out; + } + + tap = &kemari->taps[port]; + + tap->status = KEMARI_TAP_ATTACHED; + + out: + dprintk(XENLOG_DEBUG, "%s: out\n", __FUNCTION__); + return ret; +} + +static long kemari_detach(struct domain *d, + struct xen_domctl_kemari_op *kemari_op) +{ + long ret; + uint32_t port = kemari_op->u.detach.port; + struct kemari *kemari = d->kemari; + struct kemari_tap *tap = &kemari->taps[port]; + + ret = -EINVAL; + if ( unlikely(kemari == NULL) ) + { + dprintk(XENLOG_ERR, "kemari is off\n"); + goto out; + } + + ret = -EINVAL; + if ( unlikely(tap->status != KEMARI_TAP_ATTACHED) ) + goto out; + + ret = kemari_unbind_tap(d, kemari_op); + if (ret < 0) + goto out; + + tap->status = KEMARI_TAP_DETACHED; + + out: + return ret; +} + +static void share_kemari_page_with_privileged_guests(struct kemari *kemari) +{ + int i; + struct kemari_ring *ring = kemari->ring; + + for ( i = 0; i < kemari->num_pages; i++ ) + share_xen_page_with_privileged_guests(virt_to_page(ring) + i, + XENSHARE_writable); +} + +static void unshare_kemari_page_with_privileged_guests(struct kemari *kemari) +{ + int i; + + for ( i = 0; i < kemari->num_pages; i++ ) + { + struct page_info *page = mfn_to_page(kemari->mfn + i); + BUG_ON(page_get_owner(page) != dom_xen); + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) + put_page(page); + } +} + +static void kemari_free_ring(struct domain *d) +{ + int order; + struct vcpu *v = d->vcpu[0]; + struct kemari *kemari = d->kemari; + + if ( kemari->ring == NULL || + kemari->num_pages == 0 || + kemari->port == 0 ) + return; + + free_xen_event_channel(v, kemari->port); + + unshare_kemari_page_with_privileged_guests(kemari); + + order = get_order_from_pages(kemari->num_pages); + free_xenheap_pages(kemari->ring, order); + + kemari->mfn = 0; + kemari->ring = NULL; + kemari->num_pages = 0; + kemari->port = 0; +} + +static long kemari_alloc_ring(struct domain *d, struct kemari *kemari) +{ + long ret; + unsigned int order; + unsigned long num_pages; + domid_t current_domid = current->domain->domain_id; + struct vcpu *v = d->vcpu[0]; + struct kemari_ring *ring; + unsigned long dirty_bitmap_size; + uint32_t hvm_buf_size; + + ret = alloc_unbound_xen_event_channel(v, current_domid); + if ( ret < 0 ) + { + dprintk(XENLOG_ERR, "couldn't alloc xen_event_channel\n"); + goto out; + } + kemari->port = ret; + + dirty_bitmap_size = (BITS_TO_LONGS(domain_get_maximum_gpfn(d) + 1) + * sizeof(unsigned long)); + + ret = -EINVAL; + if ( dirty_bitmap_size == 0 || !mfn_valid(d->arch.paging.log_dirty.top) ) + { + dprintk(XENLOG_ERR, "dirty_bitmap is EMPTY\n"); + goto out_evtchn; + } + + hvm_buf_size = hvm_save_size(d); + num_pages = (sizeof(struct kemari_ring) + + hvm_buf_size + + (dirty_bitmap_size >> 3) + + PAGE_SIZE - 1) / PAGE_SIZE; + order = get_order_from_pages(num_pages); + num_pages = (1UL << order); + + dprintk(XENLOG_DEBUG, "ring=%u, bitmap=%lu, ctxt=%u, PAGE=%ld\n", + sizeof(struct kemari_ring), dirty_bitmap_size / 8, + hvm_buf_size, PAGE_SIZE); + + ret = -ENOMEM; + ring = alloc_xenheap_pages(order, 0); + if ( ring == NULL ) + { + dprintk(XENLOG_ERR, "couldn't alloc xenheap_pages\n"); + goto out_evtchn; + } + memset(ring, 0, PAGE_SIZE * num_pages); + + ring->num_ents = + (PAGE_SIZE * num_pages - hvm_buf_size + (long)ring - (long)ring->data) + / sizeof(struct kemari_ent); + ring->hvm_ctxt.buf_size = hvm_buf_size; + ring->hvm_ctxt.buf_offset = PAGE_SIZE * num_pages - hvm_buf_size; + + kemari->num_pages = num_pages; + kemari->mfn = virt_to_mfn(ring); + kemari->ring = ring; + + share_kemari_page_with_privileged_guests(kemari); + + dprintk(XENLOG_DEBUG, "num_ents=%u, num_pages=%u\n", + ring->num_ents, kemari->num_pages); + + return 0; + + out_evtchn: + free_xen_event_channel(v, kemari->port); + out: + return ret; +} + +static long kemari_enable(struct domain *d, + struct xen_domctl_kemari_op *kemari_op) +{ + long ret; + struct kemari *kemari; + + ret = -EBUSY; + if ( unlikely(d->kemari != NULL) ) + { + dprintk(XENLOG_ERR, "kemari already enabled\n"); + goto out; + } + + ret = -ENOMEM; + kemari = xmalloc_bytes(sizeof(struct kemari)); + if ( kemari == NULL ) + { + dprintk(XENLOG_ERR, "couldn't alloc kemari\n"); + goto out; + } + + memset(kemari, 0, sizeof(struct kemari) ); + + domain_pause_by_systemcontroller(d); + + ret = kemari_alloc_ring(d, kemari); + if ( ret < 0 ) + goto kemari_free; + + kemari_op->u.enable.port = kemari->port; + kemari_op->u.enable.mfn = kemari->mfn; + kemari_op->u.enable.num_pages = kemari->num_pages; + + dprintk(XENLOG_DEBUG, "port=%u, mfn=%llu\n", kemari->port, kemari->mfn); + + kemari->domain = d; + + d->kemari = kemari; + + kemari_send_domaininfo_ctxt(kemari->ring, d); + + domain_unpause_by_systemcontroller(d); + + dprintk(XENLOG_DEBUG, "kemari enabled\n"); + return 0; + + kemari_free: + xfree(kemari); + domain_unpause_by_systemcontroller(d); + out: + return ret; +} + +long kemari_off(struct domain *d) +{ + long ret; + uint32_t port; + struct kemari *kemari = d->kemari; + struct kemari_tap *tap; + struct evtchn_bind_tap kemari_unbind_tap; + + ret = -EINVAL; + if ( unlikely(kemari == NULL) ) + { + dprintk(XENLOG_ERR, "kemari already off\n"); + goto out; + } + + domain_pause_by_systemcontroller(d); + + kemari_unbind_tap.tap_dom = d->domain_id; + + for ( port = 0; port < NUM_KEMARI_TAPS; port++ ) { + tap = &kemari->taps[port]; + + if ( (tap->status != KEMARI_TAP_ATTACHED) || + (!port_is_valid(d, port)) ) + continue; + + kemari_unbind_tap.tap_port = port; + + if ( evtchn_unbind_tap(&kemari_unbind_tap) < 0 ) + dprintk(XENLOG_ERR, + "couldn't unbind evtchn tap port=%u\n", port); + } + + if ( kemari->ring ) + kemari_free_ring(d); + + xfree(kemari); + + d->kemari = NULL; + + domain_unpause_by_systemcontroller(d); + + return 0; + + out: + return ret; +} + +long do_kemari_op(struct domain *d, struct xen_domctl_kemari_op *kemari_op) +{ + static DEFINE_SPINLOCK(lock); + long ret; + + /* We don't support calling kemari by itself or dom0. */ + if ( d == current->domain || d == dom0 ) + { + dprintk(XENLOG_ERR, "can't attach kemari by itself or to dom0"); + return -EINVAL; + } + + spin_lock(&lock); + + switch ( kemari_op->cmd ) + { + case XEN_KEMARI_OP_enable: + ret = kemari_enable(d, kemari_op); + break; + + case XEN_KEMARI_OP_off: + ret = kemari_off(d); + break; + + case XEN_KEMARI_OP_attach: + ret = kemari_attach(d, kemari_op); + break; + + case XEN_KEMARI_OP_detach: + ret = kemari_detach(d, kemari_op); + break; + + default: + ret = -EINVAL; + break; + } + + spin_unlock(&lock); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |