socsvn commit: r307056 - in soc2016/vincenzo/head: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/modules/vmm

vincenzo at FreeBSD.org vincenzo at FreeBSD.org
Mon Aug 1 11:21:21 UTC 2016


Author: vincenzo
Date: Mon Aug  1 11:21:15 2016
New Revision: 307056
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=307056

Log:
  vmm: add support needed for ptnetmap
  
        (1) IO register handler
          (2) memory mapping of host memory in the guest memory
  
      This work was done from Stefano Garzarella on top of FreeBSD
      10-STABLE. Minor modifications were necessary to port it to
      FreeBSD 10.3.0-RELEASE.

Added:
  soc2016/vincenzo/head/sys/amd64/vmm/vmm_usermem.c
  soc2016/vincenzo/head/sys/amd64/vmm/vmm_usermem.h
Modified:
  soc2016/vincenzo/head/lib/libvmmapi/vmmapi.c
  soc2016/vincenzo/head/lib/libvmmapi/vmmapi.h
  soc2016/vincenzo/head/sys/amd64/include/vmm.h
  soc2016/vincenzo/head/sys/amd64/include/vmm_dev.h
  soc2016/vincenzo/head/sys/amd64/vmm/vmm.c
  soc2016/vincenzo/head/sys/amd64/vmm/vmm_dev.c
  soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.c
  soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.h
  soc2016/vincenzo/head/sys/modules/vmm/Makefile

Modified: soc2016/vincenzo/head/lib/libvmmapi/vmmapi.c
==============================================================================
--- soc2016/vincenzo/head/lib/libvmmapi/vmmapi.c	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/lib/libvmmapi/vmmapi.c	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/lib/libvmmapi/vmmapi.h
==============================================================================
--- soc2016/vincenzo/head/lib/libvmmapi/vmmapi.h	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/lib/libvmmapi/vmmapi.h	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/include/vmm.h
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/include/vmm.h	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/include/vmm.h	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/include/vmm_dev.h
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/include/vmm_dev.h	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/include/vmm_dev.h	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/vmm/vmm.c
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/vmm/vmm.c	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm.c	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/vmm/vmm_dev.c	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm_dev.c	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/vmm/vmm_ioport.c
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.c	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.c	Mon Aug  1 11:21:15 2016	(r307056)
@@ -97,31 +97,278 @@
 }
 #endif	/* KTR */
 
+#ifdef VMM_IOPORT_REG_HANDLER
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+static MALLOC_DEFINE(M_IOREGH, "ioregh", "bhyve ioport reg handlers");
+
+#define IOREGH_LOCK(ioregh)	mtx_lock_spin(&((ioregh)->mtx))
+#define IOREGH_UNLOCK(ioregh)	mtx_unlock_spin(&((ioregh)->mtx))
+
+#define IOPORT_MAX_REG_HANDLER	12
+
+/*
+ * 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 mtx mtx;
+	/* TODO: use hash table is better */
+	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->mtx 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 &regh[i];
+			}
+		}
+	}
+
+	return (NULL);
+}
+
+/* call with ioregh->mtx 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 &regh[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);
+
+	IOREGH_LOCK(ioregh);
+
+	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:
+	IOREGH_UNLOCK(ioregh);
+	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);
+
+	IOREGH_LOCK(ioregh);
+
+	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:
+	IOREGH_UNLOCK(ioregh);
+	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);
+
+	IOREGH_LOCK(ioregh);
+	regh = vmm_ioport_find_handler(ioregh, vmexit->u.inout.port,
+			vmexit->u.inout.in, mask_data, vmexit->u.inout.eax);
+	if (regh == NULL) {
+		IOREGH_UNLOCK(ioregh);
+		return (0);
+	}
+	*error = (*(regh->handler))(vm, regh, val);
+	IOREGH_UNLOCK(ioregh);
+	return (1);
+}
+
+struct ioregh *
+ioregh_init(struct vm *vm)
+{
+	struct ioregh *ioregh;
+
+	ioregh = malloc(sizeof(struct ioregh), M_IOREGH, M_WAITOK | M_ZERO);
+
+	mtx_init(&ioregh->mtx, "ioregh lock", NULL, MTX_SPIN);
+
+	return (ioregh);
+}
+
+void
+ioregh_cleanup(struct ioregh *ioregh)
+{
+	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/head/sys/amd64/vmm/vmm_ioport.h
==============================================================================
--- soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.h	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm_ioport.h	Mon Aug  1 11:21:15 2016	(r307056)
@@ -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/head/sys/amd64/vmm/vmm_usermem.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm_usermem.c	Mon Aug  1 11:21:15 2016	(r307056)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella at 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/sglist.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/proc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/md_var.h>
+
+#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/head/sys/amd64/vmm/vmm_usermem.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2016/vincenzo/head/sys/amd64/vmm/vmm_usermem.h	Mon Aug  1 11:21:15 2016	(r307056)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella at 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/head/sys/modules/vmm/Makefile
==============================================================================
--- soc2016/vincenzo/head/sys/modules/vmm/Makefile	Mon Aug  1 11:12:03 2016	(r307055)
+++ soc2016/vincenzo/head/sys/modules/vmm/Makefile	Mon Aug  1 11:21:15 2016	(r307056)
@@ -21,6 +21,7 @@
 	vmm_ioport.c	\
 	vmm_lapic.c	\
 	vmm_mem.c	\
+	vmm_usermem.c	\
 	vmm_stat.c	\
 	vmm_util.c	\
 	x86.c


More information about the svn-soc-all mailing list