diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 215101d046..63be3d3f0f 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -36,6 +36,7 @@ CTRL_SRCS-y += xtl_core.c CTRL_SRCS-y += xtl_logger_stdio.c CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c xc_linux_osdep.c +CTRL_SRCS-$(CONFIG_FreeBSD) += xc_freebsd.c xc_freebsd_osdep.c CTRL_SRCS-$(CONFIG_SunOS) += xc_solaris.c CTRL_SRCS-$(CONFIG_NetBSD) += xc_netbsd.c CTRL_SRCS-$(CONFIG_MiniOS) += xc_minios.c diff --git a/tools/libxc/xc_freebsd.c b/tools/libxc/xc_freebsd.c new file mode 100644 index 0000000000..8e70a918d0 --- /dev/null +++ b/tools/libxc/xc_freebsd.c @@ -0,0 +1,72 @@ +/****************************************************************************** + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "xc_private.h" + +/* Optionally flush file to disk and discard page cache */ +void discard_file_cache(xc_interface *xch, int fd, int flush) +{ + off_t cur = 0; + int saved_errno = errno; + + if ( flush && (fsync(fd) < 0) ) + goto out; + + /* + * Calculate last page boundary of amount written so far + * unless we are flushing in which case entire cache + * is discarded. + */ + if ( !flush ) + { + if ( (cur = lseek(fd, 0, SEEK_CUR)) == (off_t)-1 ) + cur = 0; + cur &= ~(XC_PAGE_SIZE-1); + } + + /* Discard from the buffer cache. */ + if ( posix_fadvise(fd, 0, cur, POSIX_FADV_DONTNEED) < 0 ) + goto out; + + out: + errno = saved_errno; +} + +void *xc_memalign(xc_interface *xch, size_t alignment, size_t size) +{ + int ret; + void *ptr; + + ret = posix_memalign(&ptr, alignment, size); + if ( ret != 0 || !ptr ) + return NULL; + + return ptr; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libxc/xc_freebsd_osdep.c b/tools/libxc/xc_freebsd_osdep.c new file mode 100644 index 0000000000..151d3bfc57 --- /dev/null +++ b/tools/libxc/xc_freebsd_osdep.c @@ -0,0 +1,405 @@ + /****************************************************************************** + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * xc_gnttab functions: + * Copyright (c) 2007-2008, D G Murray + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "xenctrl.h" +#include "xenctrlosdep.h" + +#define PRIVCMD_DEV "/dev/xen/privcmd" +#define EVTCHN_DEV "/dev/xen/evtchn" + +#define PERROR(_m, _a...) xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m \ + " (%d = %s)", ## _a , errno, xc_strerror(xch, errno)) + +/*------------------------- Privcmd device interface -------------------------*/ +static xc_osdep_handle freebsd_privcmd_open(xc_interface *xch) +{ + int flags, saved_errno; + int fd = open(PRIVCMD_DEV, O_RDWR); + + if ( fd == -1 ) + { + PERROR("Could not obtain handle on privileged command interface " + PRIVCMD_DEV); + return XC_OSDEP_OPEN_ERROR; + } + + /* + * Although we return the file handle as the 'xc handle' the API + * does not specify / guarentee that this integer is in fact + * a file handle. Thus we must take responsiblity to ensure + * it doesn't propagate (ie leak) outside the process. + */ + if ( (flags = fcntl(fd, F_GETFD)) < 0 ) + { + PERROR("Could not get file handle flags"); + goto error; + } + + flags |= FD_CLOEXEC; + + if ( fcntl(fd, F_SETFD, flags) < 0 ) + { + PERROR("Could not set file handle flags"); + goto error; + } + + return (xc_osdep_handle)fd; + + error: + saved_errno = errno; + close(fd); + errno = saved_errno; + + return XC_OSDEP_OPEN_ERROR; +} + +static int freebsd_privcmd_close(xc_interface *xch, xc_osdep_handle h) +{ + int fd = (int)h; + + return close(fd); +} + +/*------------------------ Privcmd hypercall interface -----------------------*/ +static void *freebsd_privcmd_alloc_hypercall_buffer(xc_interface *xch, + xc_osdep_handle h, + int npages) +{ + size_t size = npages * XC_PAGE_SIZE; + void *p; + + /* Address returned by mmap is page aligned. */ + p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, + -1, 0); + if (p == NULL) + return NULL; + + /* + * Since FreeBSD doesn't have the MAP_LOCKED flag, + * lock memory using mlock. + */ + if ( mlock(p, size) < 0 ) + { + munmap(p, size); + return NULL; + } + + return p; +} + +static void freebsd_privcmd_free_hypercall_buffer(xc_interface *xch, + xc_osdep_handle h, void *ptr, + int npages) +{ + + /* Unlock pages */ + munlock(ptr, npages * XC_PAGE_SIZE); + + munmap(ptr, npages * XC_PAGE_SIZE); +} + +static int freebsd_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, + privcmd_hypercall_t *hypercall) +{ + int fd = (int)h; + int ret; + + ret = ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, hypercall); + + return (ret == 0) ? hypercall->retval : ret; +} + +/*----------------------- Privcmd foreign map interface ----------------------*/ +static void *freebsd_privcmd_map_foreign_bulk(xc_interface *xch, + xc_osdep_handle h, + uint32_t dom, int prot, + const xen_pfn_t *arr, int *err, + unsigned int num) +{ + int fd = (int)h; + privcmd_mmapbatch_t ioctlx; + void *addr; + int rc; + + addr = mmap(NULL, num << XC_PAGE_SHIFT, prot, MAP_SHARED, fd, 0); + if ( addr == MAP_FAILED ) + { + PERROR("xc_map_foreign_batch: mmap failed"); + return NULL; + } + + ioctlx.num = num; + ioctlx.dom = dom; + ioctlx.addr = (unsigned long)addr; + ioctlx.arr = arr; + ioctlx.err = err; + + rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx); + if ( rc < 0 ) + { + int saved_errno = errno; + PERROR("xc_map_foreign_batch: ioctl failed"); + (void)munmap(addr, num << XC_PAGE_SHIFT); + errno = saved_errno; + return NULL; + } + + return addr; +} + +static void *freebsd_privcmd_map_foreign_range(xc_interface *xch, + xc_osdep_handle h, + uint32_t dom, int size, int prot, + unsigned long mfn) +{ + xen_pfn_t *arr; + int num; + int i; + void *ret; + + num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT; + arr = calloc(num, sizeof(xen_pfn_t)); + if ( arr == NULL ) + return NULL; + + for ( i = 0; i < num; i++ ) + arr[i] = mfn + i; + + ret = xc_map_foreign_pages(xch, dom, prot, arr, num); + free(arr); + return ret; +} + +static void *freebsd_privcmd_map_foreign_ranges(xc_interface *xch, + xc_osdep_handle h, + uint32_t dom, size_t size, + int prot, size_t chunksize, + privcmd_mmap_entry_t entries[], + int nentries) +{ + xen_pfn_t *arr; + int num_per_entry; + int num; + int i; + int j; + void *ret; + + num_per_entry = chunksize >> XC_PAGE_SHIFT; + num = num_per_entry * nentries; + arr = calloc(num, sizeof(xen_pfn_t)); + if ( arr == NULL ) + return NULL; + + for ( i = 0; i < nentries; i++ ) + for ( j = 0; j < num_per_entry; j++ ) + arr[i * num_per_entry + j] = entries[i].mfn + j; + + ret = xc_map_foreign_pages(xch, dom, prot, arr, num); + free(arr); + return ret; +} + +/*----------------------------- Privcmd handlers -----------------------------*/ +static struct xc_osdep_ops freebsd_privcmd_ops = { + .open = &freebsd_privcmd_open, + .close = &freebsd_privcmd_close, + + .u.privcmd = { + .alloc_hypercall_buffer = &freebsd_privcmd_alloc_hypercall_buffer, + .free_hypercall_buffer = &freebsd_privcmd_free_hypercall_buffer, + + .hypercall = &freebsd_privcmd_hypercall, + + .map_foreign_bulk = &freebsd_privcmd_map_foreign_bulk, + .map_foreign_range = &freebsd_privcmd_map_foreign_range, + .map_foreign_ranges = &freebsd_privcmd_map_foreign_ranges, + }, +}; + +/*-------------------------- Evtchn device interface -------------------------*/ +static xc_osdep_handle +freebsd_evtchn_open(xc_evtchn *xce) +{ + int fd = open(EVTCHN_DEV, O_RDWR); + if ( fd == -1 ) + return XC_OSDEP_OPEN_ERROR; + + return (xc_osdep_handle)fd; +} + +static int +freebsd_evtchn_close(xc_evtchn *xce, xc_osdep_handle h) +{ + int fd = (int)h; + return close(fd); +} + +static int +freebsd_evtchn_fd(xc_evtchn *xce, xc_osdep_handle h) +{ + return (int)h; +} + +/*------------------------------ Evtchn interface ----------------------------*/ +static int +freebsd_evtchn_notify(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port) +{ + int fd = (int)h; + struct ioctl_evtchn_notify notify; + + notify.port = port; + + return ioctl(fd, IOCTL_EVTCHN_NOTIFY, ¬ify); +} + +static evtchn_port_or_error_t +freebsd_evtchn_bind_unbound_port(xc_evtchn *xce, xc_osdep_handle h, int domid) +{ + int ret, fd = (int)h; + struct ioctl_evtchn_bind_unbound_port bind; + + bind.remote_domain = domid; + + ret = ioctl(fd, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind); + return ( ret == 0 ) ? bind.port : ret; +} + +static evtchn_port_or_error_t +freebsd_evtchn_bind_interdomain(xc_evtchn *xce, xc_osdep_handle h, int domid, + evtchn_port_t remote_port) +{ + int ret, fd = (int)h; + struct ioctl_evtchn_bind_interdomain bind; + + bind.remote_domain = domid; + bind.remote_port = remote_port; + + ret = ioctl(fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); + return ( ret == 0 ) ? bind.port : ret; +} + +static evtchn_port_or_error_t +freebsd_evtchn_bind_virq(xc_evtchn *xce, xc_osdep_handle h, unsigned int virq) +{ + int ret, fd = (int)h; + struct ioctl_evtchn_bind_virq bind; + + bind.virq = virq; + + ret = ioctl(fd, IOCTL_EVTCHN_BIND_VIRQ, &bind); + return ( ret == 0 ) ? bind.port : ret; +} + +static int +freebsd_evtchn_unbind(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port) +{ + int fd = (int)h; + struct ioctl_evtchn_unbind unbind; + + unbind.port = port; + + return ioctl(fd, IOCTL_EVTCHN_UNBIND, &unbind); +} + +static evtchn_port_or_error_t +freebsd_evtchn_pending(xc_evtchn *xce, xc_osdep_handle h) +{ + int fd = (int)h; + evtchn_port_t port; + + if ( read(fd, &port, sizeof(port)) != sizeof(port) ) + return -1; + + return port; +} + +static int +freebsd_evtchn_unmask(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port) +{ + int fd = (int)h; + + if ( write(fd, &port, sizeof(port)) != sizeof(port) ) + return -1; + return 0; +} + +/*----------------------------- Evtchn handlers ------------------------------*/ +static struct xc_osdep_ops freebsd_evtchn_ops = { + .open = &freebsd_evtchn_open, + .close = &freebsd_evtchn_close, + + .u.evtchn = { + .fd = &freebsd_evtchn_fd, + .notify = &freebsd_evtchn_notify, + .bind_unbound_port = &freebsd_evtchn_bind_unbound_port, + .bind_interdomain = &freebsd_evtchn_bind_interdomain, + .bind_virq = &freebsd_evtchn_bind_virq, + .unbind = &freebsd_evtchn_unbind, + .pending = &freebsd_evtchn_pending, + .unmask = &freebsd_evtchn_unmask, + }, +}; + +/*---------------------------- FreeBSD interface -----------------------------*/ +static struct xc_osdep_ops * +freebsd_osdep_init(xc_interface *xch, enum xc_osdep_type type) +{ + switch ( type ) + { + case XC_OSDEP_PRIVCMD: + return &freebsd_privcmd_ops; + case XC_OSDEP_EVTCHN: + return &freebsd_evtchn_ops; + default: + return NULL; + } +} + +xc_osdep_info_t xc_osdep_info = { + .name = "FreeBSD Native OS interface", + .init = &freebsd_osdep_init, + .fake = 0, +}; + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */