From owner-svn-soc-all@freebsd.org Sat Aug 20 20:22:27 2016 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 5AB09BC06CB for ; Sat, 20 Aug 2016 20:22:27 +0000 (UTC) (envelope-from vincenzo@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4BD441E16 for ; Sat, 20 Aug 2016 20:22:27 +0000 (UTC) (envelope-from vincenzo@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id u7KKMRFL067155 for ; Sat, 20 Aug 2016 20:22:27 GMT (envelope-from vincenzo@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id u7KKMLHU067000 for svn-soc-all@FreeBSD.org; Sat, 20 Aug 2016 20:22:21 GMT (envelope-from vincenzo@FreeBSD.org) Date: Sat, 20 Aug 2016 20:22:21 GMT Message-Id: <201608202022.u7KKMLHU067000@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to vincenzo@FreeBSD.org using -f From: vincenzo@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r308107 - in soc2016/vincenzo/current/head: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/conf sys/dev/netmap sys/modules/netmap sys/modules/vmm sys/net usr.sbin/bhyve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 20 Aug 2016 20:22:27 -0000 Author: vincenzo Date: Sat Aug 20 20:22:20 2016 New Revision: 308107 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=308107 Log: import gsoc2016-ptnet patch Added: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.c soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.h soc2016/vincenzo/current/head/sys/dev/netmap/if_nfe_netmap.h soc2016/vincenzo/current/head/sys/dev/netmap/if_ptnet.c soc2016/vincenzo/current/head/sys/dev/netmap/ptnetmap.c soc2016/vincenzo/current/head/sys/net/netmap_virt.h soc2016/vincenzo/current/head/usr.sbin/bhyve/net_backends.c soc2016/vincenzo/current/head/usr.sbin/bhyve/net_backends.h soc2016/vincenzo/current/head/usr.sbin/bhyve/net_utils.c soc2016/vincenzo/current/head/usr.sbin/bhyve/net_utils.h soc2016/vincenzo/current/head/usr.sbin/bhyve/pci_ptnetmap_memdev.c soc2016/vincenzo/current/head/usr.sbin/bhyve/pci_ptnetmap_netif.c Modified: soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.c soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.h soc2016/vincenzo/current/head/sys/amd64/include/vmm.h soc2016/vincenzo/current/head/sys/amd64/include/vmm_dev.h soc2016/vincenzo/current/head/sys/amd64/vmm/vmm.c soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_dev.c soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.c soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.h soc2016/vincenzo/current/head/sys/conf/files soc2016/vincenzo/current/head/sys/dev/netmap/if_ixl_netmap.h soc2016/vincenzo/current/head/sys/dev/netmap/if_lem_netmap.h soc2016/vincenzo/current/head/sys/dev/netmap/if_vtnet_netmap.h soc2016/vincenzo/current/head/sys/dev/netmap/ixgbe_netmap.h soc2016/vincenzo/current/head/sys/dev/netmap/netmap.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_freebsd.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_generic.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_kern.h soc2016/vincenzo/current/head/sys/dev/netmap/netmap_mbq.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_mbq.h soc2016/vincenzo/current/head/sys/dev/netmap/netmap_mem2.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_mem2.h soc2016/vincenzo/current/head/sys/dev/netmap/netmap_monitor.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_offloadings.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_pipe.c soc2016/vincenzo/current/head/sys/dev/netmap/netmap_vale.c soc2016/vincenzo/current/head/sys/modules/netmap/Makefile soc2016/vincenzo/current/head/sys/modules/vmm/Makefile soc2016/vincenzo/current/head/sys/net/netmap.h soc2016/vincenzo/current/head/sys/net/netmap_user.h soc2016/vincenzo/current/head/usr.sbin/bhyve/Makefile soc2016/vincenzo/current/head/usr.sbin/bhyve/pci_virtio_net.c Modified: soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.c ============================================================================== --- soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.c Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.c Sat Aug 20 20:22:20 2016 (r308107) @@ -883,6 +883,42 @@ } int +vm_get_fd(struct vmctx *ctx) +{ + return (ctx->fd); +} + +int +vm_map_user_buf(struct vmctx *ctx, vm_paddr_t gpa, size_t len, void *host_buf) +{ + struct vm_user_buf user_buf; + + bzero(&user_buf, sizeof(user_buf)); + user_buf.gpa = gpa; + user_buf.len = len; + user_buf.addr = host_buf; + + return (ioctl(ctx->fd, VM_MAP_USER_BUF, &user_buf)); +} + +int +vm_io_reg_handler(struct vmctx *ctx, uint16_t port, uint16_t in, uint32_t mask_data, uint32_t data, + enum vm_io_regh_type type, void *arg) +{ + struct vm_io_reg_handler ioregh; + + bzero(&ioregh, sizeof(ioregh)); + ioregh.port = port; + ioregh.in = in; + ioregh.mask_data = mask_data; + ioregh.data = data; + ioregh.type = type; + ioregh.arg = arg; + + return (ioctl(ctx->fd, VM_IO_REG_HANDLER, &ioregh)); +} + +int vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, uint64_t addr, uint64_t msg, int numvec) { Modified: soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.h ============================================================================== --- soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/lib/libvmmapi/vmmapi.h Sat Aug 20 20:22:20 2016 (r308107) @@ -161,7 +161,10 @@ int vm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *i1, uint64_t *i2); int vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t exit_intinfo); - +int vm_get_fd(struct vmctx *ctx); +int vm_map_user_buf(struct vmctx *ctx, vm_paddr_t gpa, size_t len, void *host_buf); +int vm_io_reg_handler(struct vmctx *ctx, uint16_t port, uint16_t in, + uint32_t mask_data, uint32_t data, enum vm_io_regh_type type, void *arg); /* * Return a pointer to the statistics buffer. Note that this is not MT-safe. */ Modified: soc2016/vincenzo/current/head/sys/amd64/include/vmm.h ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/include/vmm.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/include/vmm.h Sat Aug 20 20:22:20 2016 (r308107) @@ -183,6 +183,7 @@ int vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem); void vm_free_memseg(struct vm *vm, int ident); int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa); +int vm_map_usermem(struct vm *vm, vm_paddr_t gpa, size_t len, void *buf, struct thread *td); int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len); int vm_assign_pptdev(struct vm *vm, int bus, int slot, int func); int vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func); @@ -321,6 +322,7 @@ struct vatpit *vm_atpit(struct vm *vm); struct vpmtmr *vm_pmtmr(struct vm *vm); struct vrtc *vm_rtc(struct vm *vm); +struct ioregh *vm_ioregh(struct vm *vm); /* * Inject exception 'vector' into the guest vcpu. This function returns 0 on @@ -417,7 +419,13 @@ EDGE_TRIGGER, LEVEL_TRIGGER }; - + +enum vm_io_regh_type { + VM_IO_REGH_DELETE, + VM_IO_REGH_KWEVENTS, /* kernel wait events */ + VM_IO_REGH_MAX +}; + /* * The 'access' field has the format specified in Table 21-2 of the Intel * Architecture Manual vol 3b. Modified: soc2016/vincenzo/current/head/sys/amd64/include/vmm_dev.h ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/include/vmm_dev.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/include/vmm_dev.h Sat Aug 20 20:22:20 2016 (r308107) @@ -123,6 +123,21 @@ size_t len; }; +struct vm_user_buf { + vm_paddr_t gpa; + void *addr; + size_t len; +}; + +struct vm_io_reg_handler { + uint16_t port; /* I/O address */ + uint16_t in; /* 0 out, 1 in */ + uint32_t mask_data; /* 0 means match anything */ + uint32_t data; /* data to match */ + enum vm_io_regh_type type; /* handler type */ + void *arg; /* handler argument */ +}; + struct vm_pptdev_msi { int vcpu; int bus; @@ -286,6 +301,10 @@ IOCNUM_RTC_WRITE = 101, IOCNUM_RTC_SETTIME = 102, IOCNUM_RTC_GETTIME = 103, + + /* host mmap and IO handler */ + IOCNUM_MAP_USER_BUF = 104, + IOCNUM_IO_REG_HANDLER = 105, }; #define VM_RUN \ @@ -344,6 +363,10 @@ _IOW('v', IOCNUM_UNBIND_PPTDEV, struct vm_pptdev) #define VM_MAP_PPTDEV_MMIO \ _IOW('v', IOCNUM_MAP_PPTDEV_MMIO, struct vm_pptdev_mmio) +#define VM_MAP_USER_BUF \ + _IOW('v', IOCNUM_MAP_USER_BUF, struct vm_user_buf) +#define VM_IO_REG_HANDLER \ + _IOW('v', IOCNUM_IO_REG_HANDLER, struct vm_io_reg_handler) #define VM_PPTDEV_MSI \ _IOW('v', IOCNUM_PPTDEV_MSI, struct vm_pptdev_msi) #define VM_PPTDEV_MSIX \ Modified: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm.c ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/vmm/vmm.c Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm.c Sat Aug 20 20:22:20 2016 (r308107) @@ -66,6 +66,7 @@ #include "vmm_ktr.h" #include "vmm_host.h" #include "vmm_mem.h" +#include "vmm_usermem.h" #include "vmm_util.h" #include "vatpic.h" #include "vatpit.h" @@ -148,6 +149,7 @@ struct vatpit *vatpit; /* (i) virtual atpit */ struct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */ struct vrtc *vrtc; /* (o) virtual RTC */ + struct ioregh *ioregh; /* () I/O reg handler */ volatile cpuset_t active_cpus; /* (i) active vcpus */ int suspend; /* (i) stop VM execution */ volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ @@ -419,6 +421,7 @@ vm->vpmtmr = vpmtmr_init(vm); if (create) vm->vrtc = vrtc_init(vm); + vm->ioregh = ioregh_init(vm); CPU_ZERO(&vm->active_cpus); @@ -475,11 +478,13 @@ vrtc_cleanup(vm->vrtc); else vrtc_reset(vm->vrtc); + ioregh_cleanup(vm->ioregh); vpmtmr_cleanup(vm->vpmtmr); vatpit_cleanup(vm->vatpit); vhpet_cleanup(vm->vhpet); vatpic_cleanup(vm->vatpic); vioapic_cleanup(vm->vioapic); + vmm_usermem_cleanup(vm->vmspace); for (i = 0; i < VM_MAXCPU; i++) vcpu_cleanup(vm, i, destroy); @@ -553,6 +558,17 @@ } int +vm_map_usermem(struct vm *vm, vm_paddr_t gpa, size_t len, void *buf, struct thread *td) +{ + vm_object_t obj; + + if ((obj = vmm_usermem_alloc(vm->vmspace, gpa, len, buf, td)) == NULL) + return (ENOMEM); + + return (0); +} + +int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) { @@ -588,6 +604,9 @@ if (ppt_is_mmio(vm, gpa)) return (true); /* 'gpa' is pci passthru mmio */ + if (usermem_mapped(vm->vmspace, gpa)) + return (true); /* 'gpa' is user-space buffer mapped */ + return (false); } @@ -2457,6 +2476,12 @@ return (vm->vrtc); } +struct ioregh * +vm_ioregh(struct vm *vm) +{ + return (vm->ioregh); +} + enum vm_reg_name vm_segment_name(int seg) { Modified: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_dev.c ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_dev.c Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_dev.c Sat Aug 20 20:22:20 2016 (r308107) @@ -55,6 +55,7 @@ #include "vmm_lapic.h" #include "vmm_stat.h" #include "vmm_mem.h" +#include "vmm_ioport.h" #include "io/ppt.h" #include "io/vatpic.h" #include "io/vioapic.h" @@ -300,6 +301,8 @@ struct vm_pptdev_mmio *pptmmio; struct vm_pptdev_msi *pptmsi; struct vm_pptdev_msix *pptmsix; + struct vm_user_buf *usermem; + struct vm_io_reg_handler *ioregh; struct vm_nmi *vmnmi; struct vm_stats *vmstats; struct vm_stat_desc *statdesc; @@ -358,6 +361,7 @@ case VM_UNBIND_PPTDEV: case VM_ALLOC_MEMSEG: case VM_MMAP_MEMSEG: + case VM_MAP_USER_BUF: case VM_REINIT: /* * ioctls that operate on the entire virtual machine must @@ -433,6 +437,16 @@ pptmmio->func, pptmmio->gpa, pptmmio->len, pptmmio->hpa); break; + case VM_MAP_USER_BUF: + usermem = (struct vm_user_buf *)data; + error = vm_map_usermem(sc->vm, usermem->gpa, usermem->len, + usermem->addr, td); + break; + case VM_IO_REG_HANDLER: + ioregh = (struct vm_io_reg_handler *)data; + error = vmm_ioport_reg_handler(sc->vm, ioregh->port, ioregh->in, ioregh->mask_data, + ioregh->data, ioregh->type, ioregh->arg); + break; case VM_BIND_PPTDEV: pptdev = (struct vm_pptdev *)data; error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot, Modified: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.c ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.c Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.c Sat Aug 20 20:22:20 2016 (r308107) @@ -97,31 +97,274 @@ } #endif /* KTR */ +#ifdef VMM_IOPORT_REG_HANDLER +#include +#include +#include +#include +#include +#include + +static MALLOC_DEFINE(M_IOREGH, "ioregh", "bhyve ioport reg handlers"); + +#define IOPORT_MAX_REG_HANDLER 16 + +/* + * ioport_reg_handler functions allows us to to catch VM write/read + * on specific I/O address and send notification. + * + * When the VM writes or reads a specific value on I/O address, if the address + * and the value matches with the info stored durign the handler registration, + * then we send a notification (we can have multiple type of notification, + * but for now is implemented only the VM_IO_REGH_KWEVENTS handler. + */ + +typedef int (*ioport_reg_handler_func_t)(struct vm *vm, + struct ioport_reg_handler *regh, uint32_t *val); + +struct ioport_reg_handler { + uint16_t port; /* I/O address */ + uint16_t in; /* 0 out, 1 in */ + uint32_t mask_data; /* 0 means match anything */ + uint32_t data; /* data to match */ + ioport_reg_handler_func_t handler; /* handler pointer */ + void *handler_arg; /* handler argument */ +}; + +struct ioregh { + struct sx lock; + /* TODO: use hash table */ + struct ioport_reg_handler handlers[IOPORT_MAX_REG_HANDLER]; +}; + +/* ----- I/O reg handlers ----- */ + +/* + * VM_IO_REGH_KWEVENTS handler + * + * wakeup() on specified address that uniquely identifies the event + * + */ +static int +vmm_ioport_reg_wakeup(struct vm *vm, struct ioport_reg_handler *regh, uint32_t *val) +{ + wakeup(regh->handler_arg); + return (0); +} + +/* + * TODO: + * - VM_IO_REGH_CONDSIGNAL: pthread_cond_signal + * - VM_IO_REGH_WRITEFD: write on fd + * - VM_IO_REGH_IOCTL: ioctl on fd + */ + +/* call with ioregh->lock held */ +static struct ioport_reg_handler * +vmm_ioport_find_handler(struct ioregh *ioregh, uint16_t port, uint16_t in, + uint32_t mask_data, uint32_t data) +{ + struct ioport_reg_handler *regh; + uint32_t mask; + int i; + + regh = ioregh->handlers; + for (i = 0; i < IOPORT_MAX_REG_HANDLER; i++) { + if (regh[i].handler != NULL) { + mask = regh[i].mask_data & mask_data; + if ((regh[i].port == port) && (regh[i].in == in) + && ((mask & regh[i].data) == (mask & data))) { + return ®h[i]; + } + } + } + + return (NULL); +} + +/* call with ioregh->lock held */ +static struct ioport_reg_handler * +vmm_ioport_empty_handler(struct ioregh *ioregh) +{ + struct ioport_reg_handler *regh; + int i; + + regh = ioregh->handlers; + for (i = 0; i < IOPORT_MAX_REG_HANDLER; i++) { + if (regh[i].handler == NULL) { + return ®h[i]; + } + } + + return (NULL); +} + + +static int +vmm_ioport_add_handler(struct vm *vm, uint16_t port, uint16_t in, uint32_t mask_data, + uint32_t data, ioport_reg_handler_func_t handler, void *handler_arg) +{ + struct ioport_reg_handler *regh; + struct ioregh *ioregh; + int ret = 0; + + ioregh = vm_ioregh(vm); + + sx_xlock(&ioregh->lock); + + regh = vmm_ioport_find_handler(ioregh, port, in, mask_data, data); + if (regh != NULL) { + printf("%s: handler for port %d in %d mask_data %d data %d \ + already registered\n", + __FUNCTION__, port, in, mask_data, data); + ret = EEXIST; + goto err; + } + + regh = vmm_ioport_empty_handler(ioregh); + if (regh == NULL) { + printf("%s: empty reg_handler slot not found\n", __FUNCTION__); + ret = ENOMEM; + goto err; + } + + regh->port = port; + regh->in = in; + regh->mask_data = mask_data; + regh->data = data; + regh->handler = handler; + regh->handler_arg = handler_arg; + +err: + sx_xunlock(&ioregh->lock); + return (ret); +} + +static int +vmm_ioport_del_handler(struct vm *vm, uint16_t port, uint16_t in, + uint32_t mask_data, uint32_t data) +{ + struct ioport_reg_handler *regh; + struct ioregh *ioregh; + int ret = 0; + + ioregh = vm_ioregh(vm); + + sx_xlock(&ioregh->lock); + + regh = vmm_ioport_find_handler(ioregh, port, in, mask_data, data); + + if (regh == NULL) { + ret = EINVAL; + goto err; + } + + bzero(regh, sizeof(struct ioport_reg_handler)); +err: + sx_xunlock(&ioregh->lock); + return (ret); +} + +/* + * register or delete a new I/O event handler. + */ +int +vmm_ioport_reg_handler(struct vm *vm, uint16_t port, uint16_t in, + uint32_t mask_data, uint32_t data, enum vm_io_regh_type type, void *arg) +{ + int ret = 0; + + switch (type) { + case VM_IO_REGH_DELETE: + ret = vmm_ioport_del_handler(vm, port, in, mask_data, data); + break; + case VM_IO_REGH_KWEVENTS: + ret = vmm_ioport_add_handler(vm, port, in, mask_data, data, + vmm_ioport_reg_wakeup, arg); + break; + default: + printf("%s: unknown reg_handler type\n", __FUNCTION__); + ret = EINVAL; + break; + } + + return (ret); +} + +/* + * Invoke an handler, if the data matches. + */ +static int +invoke_reg_handler(struct vm *vm, int vcpuid, struct vm_exit *vmexit, + uint32_t *val, int *error) +{ + struct ioport_reg_handler *regh; + struct ioregh *ioregh; + uint32_t mask_data; + + mask_data = vie_size2mask(vmexit->u.inout.bytes); + ioregh = vm_ioregh(vm); + + sx_slock(&ioregh->lock); + regh = vmm_ioport_find_handler(ioregh, vmexit->u.inout.port, + vmexit->u.inout.in, mask_data, vmexit->u.inout.eax); + if (regh != NULL) { + *error = (*(regh->handler))(vm, regh, val); + } + sx_sunlock(&ioregh->lock); + return (regh != NULL); +} + +struct ioregh * +ioregh_init(struct vm *vm) +{ + struct ioregh *ioregh; + + ioregh = malloc(sizeof(struct ioregh), M_IOREGH, M_WAITOK | M_ZERO); + sx_init(&ioregh->lock, "ioregh lock"); + + return (ioregh); +} + +void +ioregh_cleanup(struct ioregh *ioregh) +{ + sx_destroy(&ioregh->lock); + free(ioregh, M_IOREGH); +} +#else /* !VMM_IOPORT_REG_HANDLER */ +#define invoke_reg_handler(_1, _2, _3, _4, _5) (0) +#endif /* VMM_IOPORT_REG_HANDLER */ + static int emulate_inout_port(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) { ioport_handler_func_t handler; uint32_t mask, val; - int error; + int regh = 0, error = 0; /* * If there is no handler for the I/O port then punt to userspace. */ - if (vmexit->u.inout.port >= MAX_IOPORTS || - (handler = ioport_handler[vmexit->u.inout.port]) == NULL) { + if ((vmexit->u.inout.port >= MAX_IOPORTS || + (handler = ioport_handler[vmexit->u.inout.port]) == NULL) && + (regh = invoke_reg_handler(vm, vcpuid, vmexit, &val, &error)) == 0) { *retu = true; return (0); } - mask = vie_size2mask(vmexit->u.inout.bytes); + if (!regh) { + mask = vie_size2mask(vmexit->u.inout.bytes); + + if (!vmexit->u.inout.in) { + val = vmexit->u.inout.eax & mask; + } - if (!vmexit->u.inout.in) { - val = vmexit->u.inout.eax & mask; + error = (*handler)(vm, vcpuid, vmexit->u.inout.in, + vmexit->u.inout.port, vmexit->u.inout.bytes, &val); } - error = (*handler)(vm, vcpuid, vmexit->u.inout.in, - vmexit->u.inout.port, vmexit->u.inout.bytes, &val); if (error) { /* * The value returned by this function is also the return value Modified: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.h ============================================================================== --- soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_ioport.h Sat Aug 20 20:22:20 2016 (r308107) @@ -29,6 +29,22 @@ #ifndef _VMM_IOPORT_H_ #define _VMM_IOPORT_H_ +#define VMM_IOPORT_REG_HANDLER +#ifdef VMM_IOPORT_REG_HANDLER +struct ioport_reg_handler; +struct ioregh; + +struct ioregh *ioregh_init(struct vm *vm); +void ioregh_cleanup(struct ioregh *ioregh); + +int vmm_ioport_reg_handler(struct vm *vm, uint16_t port, uint16_t in, + uint32_t mask_data, uint32_t data, enum vm_io_regh_type type, void *arg); +#else /* !VMM_IOPORT_REG_HANDLER */ +#define ioregh_init(_1) (NULL) +#define ioregh_cleanup(_1) +#define vmm_ioport_reg_handler(_1, _2, _3, _4,_5, _6, _7) (EINVAL) +#endif /* VMM_IOPORT_REG_HANDLER */ + typedef int (*ioport_handler_func_t)(struct vm *vm, int vcpuid, bool in, int port, int bytes, uint32_t *val); Added: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.c Sat Aug 20 20:22:20 2016 (r308107) @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vmm_mem.h" +#include "vmm_usermem.h" + +/* + * usermem functions allow us to map an host userspace buffer (eg. from bhyve) + * in the guest VM. + * + * This feature is used to implement ptnetmap on bhyve, mapping the netmap memory + * (returned by the mmap() in the byvhe userspace application) in the guest VM. + */ + +/* TODO: we can create a dynamical list of usermem */ +#define MAX_USERMEMS 64 + +static struct usermem { + struct vmspace *vmspace; /* guest address space */ + vm_paddr_t gpa; /* guest physical address */ + size_t len; +} usermems[MAX_USERMEMS]; + +static int +vmm_usermem_add(struct vmspace *vmspace, vm_paddr_t gpa, size_t len) +{ + int i; + + for (i = 0; i < MAX_USERMEMS; i++) { + if (usermems[i].len == 0) { + usermems[i].vmspace = vmspace; + usermems[i].gpa = gpa; + usermems[i].len = len; + break; + } + } + + if (i == MAX_USERMEMS) { + printf("vmm_usermem_add: empty usermem slot not found\n"); + return (ENOMEM); + } + + return 0; +} + +static int +vmm_usermem_del(struct vmspace *vmspace, vm_paddr_t gpa, size_t len) +{ + int i; + + for (i = 0; i < MAX_USERMEMS; i++) { + if (usermems[i].vmspace == vmspace && usermems[i].gpa == gpa + && usermems[i].len == len) { + bzero(&usermems[i], sizeof(struct usermem)); + return 1; + } + } + + return 0; +} + +boolean_t +usermem_mapped(struct vmspace *vmspace, vm_paddr_t gpa) +{ + int i; + + for (i = 0; i < MAX_USERMEMS; i++) { + if (usermems[i].vmspace != vmspace || usermems[i].len == 0) + continue; + if (gpa >= usermems[i].gpa && + gpa < usermems[i].gpa + usermems[i].len) + return (TRUE); + } + return (FALSE); +} + +vm_object_t +vmm_usermem_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len, + void *buf, struct thread *td) +{ + int error; + vm_object_t obj; + vm_map_t map; + vm_map_entry_t entry; + vm_pindex_t index; + vm_prot_t prot; + boolean_t wired; + + map = &td->td_proc->p_vmspace->vm_map; + /* lookup the vm_object that describe user addr */ + error = vm_map_lookup(&map, (unsigned long)buf, VM_PROT_RW, &entry, + &obj, &index, &prot, &wired); + + /* map th vm_object in the vmspace */ + if (obj != NULL) { + error = vm_map_find(&vmspace->vm_map, obj, index, &gpa, len, 0, + VMFS_NO_SPACE, VM_PROT_RW, VM_PROT_RW, 0); + if (error != KERN_SUCCESS) { + vm_object_deallocate(obj); + obj = NULL; + } + } + vm_map_lookup_done(map, entry); + + /* acquire the reference to the vm_object */ + if (obj != NULL) { + vm_object_reference(obj); + vmm_usermem_add(vmspace, gpa, len); + } + + return (obj); +} + +void +vmm_usermem_free(struct vmspace *vmspace, vm_paddr_t gpa, size_t len) +{ + int ret; + + ret = vmm_usermem_del(vmspace, gpa, len); + if (ret) { + //TODO check return value of vm_map_remove ? + vm_map_remove(&vmspace->vm_map, gpa, gpa + len); + //TODO should we call vm_object_deallocate ? + } +} + +void +vmm_usermem_cleanup(struct vmspace *vmspace) +{ + int i; + + for (i = 0; i < MAX_USERMEMS; i++) { + if (usermems[i].vmspace == vmspace) { + //TODO same as above + vm_map_remove(&vmspace->vm_map, usermems[i].gpa, + usermems[i].gpa + usermems[i].len); + bzero(&usermems[i], sizeof(struct usermem)); + } + } +} Added: soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2016/vincenzo/current/head/sys/amd64/vmm/vmm_usermem.h Sat Aug 20 20:22:20 2016 (r308107) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VMM_USERMEM_H_ +#define _VMM_USERMEM_H_ + +struct vm; + +struct vm_object *vmm_usermem_alloc(struct vmspace *, vm_paddr_t gpa, + size_t len, void *buf, struct thread *td); +void vmm_usermem_free(struct vmspace *, vm_paddr_t gpa, size_t len); +void vmm_usermem_cleanup(struct vmspace *); +boolean_t usermem_mapped(struct vmspace *, vm_paddr_t gpa); + +#endif Modified: soc2016/vincenzo/current/head/sys/conf/files ============================================================================== --- soc2016/vincenzo/current/head/sys/conf/files Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/conf/files Sat Aug 20 20:22:20 2016 (r308107) @@ -2166,6 +2166,7 @@ dev/ncr/ncr.c optional ncr pci dev/ncv/ncr53c500.c optional ncv dev/ncv/ncr53c500_pccard.c optional ncv pccard +dev/netmap/if_ptnet.c optional netmap dev/netmap/netmap.c optional netmap dev/netmap/netmap_freebsd.c optional netmap dev/netmap/netmap_generic.c optional netmap @@ -2175,6 +2176,7 @@ dev/netmap/netmap_offloadings.c optional netmap dev/netmap/netmap_pipe.c optional netmap dev/netmap/netmap_vale.c optional netmap +dev/netmap/ptnetmap.c optional netmap # compile-with "${NORMAL_C} -Wconversion -Wextra" dev/nfsmb/nfsmb.c optional nfsmb pci dev/nge/if_nge.c optional nge Modified: soc2016/vincenzo/current/head/sys/dev/netmap/if_ixl_netmap.h ============================================================================== --- soc2016/vincenzo/current/head/sys/dev/netmap/if_ixl_netmap.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/dev/netmap/if_ixl_netmap.h Sat Aug 20 20:22:20 2016 (r308107) @@ -59,7 +59,7 @@ /* * device-specific sysctl variables: * - * ixl_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. + * ixl_crcstrip: 0: NIC keeps CRC in rx frames (default), 1: NIC strips it. * During regular operations the CRC is stripped, but on some * hardware reception of frames not multiple of 64 is slower, * so using crcstrip=0 helps in benchmarks. @@ -74,7 +74,7 @@ int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip = 1; #if 0 SYSCTL_INT(_dev_netmap, OID_AUTO, ixl_crcstrip, - CTLFLAG_RW, &ixl_crcstrip, 1, "strip CRC on rx frames"); + CTLFLAG_RW, &ixl_crcstrip, 1, "NIC strips CRC on rx frames"); #endif SYSCTL_INT(_dev_netmap, OID_AUTO, ixl_rx_miss, CTLFLAG_RW, &ixl_rx_miss, 0, "potentially missed rx intr"); Modified: soc2016/vincenzo/current/head/sys/dev/netmap/if_lem_netmap.h ============================================================================== --- soc2016/vincenzo/current/head/sys/dev/netmap/if_lem_netmap.h Sat Aug 20 19:48:03 2016 (r308106) +++ soc2016/vincenzo/current/head/sys/dev/netmap/if_lem_netmap.h Sat Aug 20 20:22:20 2016 (r308107) @@ -38,6 +38,10 @@ #include #include /* vtophys ? */ #include +#ifdef WITH_PTNETMAP_GUEST +#include +#endif +#include extern int netmap_adaptive_io; @@ -80,6 +84,20 @@ return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); } +static void +lem_netmap_intr(struct netmap_adapter *na, int onoff) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + + EM_CORE_LOCK(adapter); + if (onoff) { + lem_enable_intr(adapter); + } else { + lem_disable_intr(adapter); + } + EM_CORE_UNLOCK(adapter); +} /* * Reconcile kernel and user view of the transmit ring. @@ -470,6 +488,176 @@ return netmap_ring_reinit(kring); } +#if defined (NIC_PTNETMAP) && defined (WITH_PTNETMAP_GUEST) +/* + * ptnetmap support for: lem (FreeBSD version) + * + * For details on ptnetmap support please see if_vtnet_netmap.h + */ +static uint32_t lem_ptnetmap_ptctl(struct ifnet *, uint32_t); + +/* Returns device configuration from the CSB */ +static int +lem_ptnetmap_config(struct netmap_adapter *na, + u_int *txr, u_int *txd, u_int *rxr, u_int *rxd) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + struct paravirt_csb *csb = adapter->csb; + int ret; + + if (csb == NULL) + return EINVAL; + + ret = lem_ptnetmap_ptctl(ifp, PTNETMAP_PTCTL_CONFIG); + if (ret) + return ret; + + *txr = 1; //*txr = csb->num_tx_rings; + *rxr = 1; //*rxr = csb->num_rx_rings; + *txd = csb->num_tx_slots; + *rxd = csb->num_rx_slots; + + D("txr %u rxr %u txd %u rxd %u", + *txr, *rxr, *txd, *rxd); + + return 0; +} + +/* Reconcile host and guest view of the transmit ring. */ +static int +lem_ptnetmap_txsync(struct netmap_kring *kring, int flags) +{ + struct netmap_adapter *na = kring->na; + //u_int ring_nr = kring->ring_id; + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + bool notify; + + notify = netmap_pt_guest_txsync(&adapter->csb->tx_ring, kring, flags); + if (notify) + E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), 0); + + return 0; +} + +/* Reconcile host and guest view of the receive ring. */ +static int +lem_ptnetmap_rxsync(struct netmap_kring *kring, int flags) +{ + struct netmap_adapter *na = kring->na; + //u_int ring_nr = kring->ring_id; + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + bool notify; + + notify = netmap_pt_guest_rxsync(&adapter->csb->rx_ring, kring, flags); + if (notify) + E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), 0); + + return 0; +} + +/* Register/unregister. We are already under netmap lock. */ +static int +lem_ptnetmap_reg(struct netmap_adapter *na, int onoff) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + struct paravirt_csb *csb = adapter->csb; + struct netmap_kring *kring; + int ret; + + if (onoff) { + ret = lem_ptnetmap_ptctl(ifp, PTNETMAP_PTCTL_REGIF); + if (ret) + return ret; + + na->na_flags |= NAF_NETMAP_ON; + adapter->ptnetmap_enabled = 1; + /* + * Init ring and kring pointers + * After PARAVIRT_PTCTL_REGIF, the csb contains a snapshot of a + * host kring pointers. + * XXX This initialization is required, because we don't close + * the host port on UNREGIF. + */ + + // Init rx ring + kring = na->rx_rings; + kring->rhead = kring->ring->head = csb->rx_ring.head; + kring->rcur = kring->ring->cur = csb->rx_ring.cur; + kring->nr_hwcur = csb->rx_ring.hwcur; + kring->nr_hwtail = kring->rtail = kring->ring->tail = + csb->rx_ring.hwtail; + + // Init tx ring + kring = na->tx_rings; + kring->rhead = kring->ring->head = csb->tx_ring.head; + kring->rcur = kring->ring->cur = csb->tx_ring.cur; + kring->nr_hwcur = csb->tx_ring.hwcur; + kring->nr_hwtail = kring->rtail = kring->ring->tail = + csb->tx_ring.hwtail; + } else { + na->na_flags &= ~NAF_NETMAP_ON; + adapter->ptnetmap_enabled = 0; + ret = lem_ptnetmap_ptctl(ifp, PTNETMAP_PTCTL_UNREGIF); + } + + return lem_netmap_reg(na, onoff); +} + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***