aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/vmm/vmm_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/vmm/vmm_dev.c')
-rw-r--r--sys/dev/vmm/vmm_dev.c114
1 files changed, 98 insertions, 16 deletions
diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c
index 4961b21180e1..d6543bf6534e 100644
--- a/sys/dev/vmm/vmm_dev.c
+++ b/sys/dev/vmm/vmm_dev.c
@@ -14,8 +14,11 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/queue.h>
+#include <sys/smp.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/ucred.h>
@@ -77,6 +80,8 @@ struct vmmdev_softc {
int flags;
};
+static bool vmm_initialized = false;
+
static SLIST_HEAD(, vmmdev_softc) head;
static unsigned pr_allow_flag;
@@ -87,6 +92,10 @@ static MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev");
SYSCTL_DECL(_hw_vmm);
+u_int vm_maxcpu;
+SYSCTL_UINT(_hw_vmm, OID_AUTO, maxcpu, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &vm_maxcpu, 0, "Maximum number of vCPUs");
+
static void devmem_destroy(void *arg);
static int devmem_create_cdev(struct vmmdev_softc *sc, int id, char *devmem);
@@ -470,6 +479,12 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
if (ioctl == NULL)
return (ENOTTY);
+ if ((ioctl->flags & VMMDEV_IOCTL_PRIV_CHECK_DRIVER) != 0) {
+ error = priv_check(td, PRIV_DRIVER);
+ if (error != 0)
+ return (error);
+ }
+
if ((ioctl->flags & VMMDEV_IOCTL_XLOCK_MEMSEGS) != 0)
vm_xlock_memsegs(sc->vm);
else if ((ioctl->flags & VMMDEV_IOCTL_SLOCK_MEMSEGS) != 0)
@@ -612,20 +627,16 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
}
error = domainset_populate(&domain, mask, mseg->ds_policy,
mseg->ds_mask_size);
- if (error) {
- free(mask, M_VMMDEV);
+ free(mask, M_VMMDEV);
+ if (error)
break;
- }
domainset = domainset_create(&domain);
if (domainset == NULL) {
error = EINVAL;
- free(mask, M_VMMDEV);
break;
}
- free(mask, M_VMMDEV);
}
error = alloc_memseg(sc, mseg, sizeof(mseg->name), domainset);
-
break;
}
case VM_GET_MEMSEG:
@@ -656,10 +667,10 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
error = EINVAL;
break;
}
- regvals = malloc(sizeof(regvals[0]) * vmregset->count, M_VMMDEV,
- M_WAITOK);
- regnums = malloc(sizeof(regnums[0]) * vmregset->count, M_VMMDEV,
- M_WAITOK);
+ regvals = mallocarray(vmregset->count, sizeof(regvals[0]),
+ M_VMMDEV, M_WAITOK);
+ regnums = mallocarray(vmregset->count, sizeof(regnums[0]),
+ M_VMMDEV, M_WAITOK);
error = copyin(vmregset->regnums, regnums, sizeof(regnums[0]) *
vmregset->count);
if (error == 0)
@@ -682,10 +693,10 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
error = EINVAL;
break;
}
- regvals = malloc(sizeof(regvals[0]) * vmregset->count, M_VMMDEV,
- M_WAITOK);
- regnums = malloc(sizeof(regnums[0]) * vmregset->count, M_VMMDEV,
- M_WAITOK);
+ regvals = mallocarray(vmregset->count, sizeof(regvals[0]),
+ M_VMMDEV, M_WAITOK);
+ regnums = mallocarray(vmregset->count, sizeof(regnums[0]),
+ M_VMMDEV, M_WAITOK);
error = copyin(vmregset->regnums, regnums, sizeof(regnums[0]) *
vmregset->count);
if (error == 0)
@@ -978,6 +989,9 @@ vmmdev_create(const char *name, struct ucred *cred)
struct vm *vm;
int error;
+ if (name == NULL || strlen(name) > VM_MAX_NAMELEN)
+ return (EINVAL);
+
sx_xlock(&vmmdev_mtx);
sc = vmmdev_lookup(name, cred);
if (sc != NULL) {
@@ -1018,6 +1032,9 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
char *buf;
int error, buflen;
+ if (!vmm_initialized)
+ return (ENXIO);
+
error = vmm_priv_check(req->td->td_ucred);
if (error != 0)
return (error);
@@ -1103,7 +1120,7 @@ static struct cdevsw vmmctlsw = {
.d_ioctl = vmmctl_ioctl,
};
-int
+static int
vmmdev_init(void)
{
int error;
@@ -1119,7 +1136,7 @@ vmmdev_init(void)
return (error);
}
-int
+static int
vmmdev_cleanup(void)
{
sx_xlock(&vmmdev_mtx);
@@ -1137,6 +1154,71 @@ vmmdev_cleanup(void)
}
static int
+vmm_handler(module_t mod, int what, void *arg)
+{
+ int error;
+
+ switch (what) {
+ case MOD_LOAD:
+ error = vmmdev_init();
+ if (error != 0)
+ break;
+
+ vm_maxcpu = mp_ncpus;
+ TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu);
+ if (vm_maxcpu > VM_MAXCPU) {
+ printf("vmm: vm_maxcpu clamped to %u\n", VM_MAXCPU);
+ vm_maxcpu = VM_MAXCPU;
+ }
+ if (vm_maxcpu == 0)
+ vm_maxcpu = 1;
+
+ error = vmm_modinit();
+ if (error == 0)
+ vmm_initialized = true;
+ else {
+ error = vmmdev_cleanup();
+ KASSERT(error == 0,
+ ("%s: vmmdev_cleanup failed: %d", __func__, error));
+ }
+ break;
+ case MOD_UNLOAD:
+ error = vmmdev_cleanup();
+ if (error == 0 && vmm_initialized) {
+ error = vmm_modcleanup();
+ if (error) {
+ /*
+ * Something bad happened - prevent new
+ * VMs from being created
+ */
+ vmm_initialized = false;
+ }
+ }
+ break;
+ default:
+ error = 0;
+ break;
+ }
+ return (error);
+}
+
+static moduledata_t vmm_kmod = {
+ "vmm",
+ vmm_handler,
+ NULL
+};
+
+/*
+ * vmm initialization has the following dependencies:
+ *
+ * - Initialization requires smp_rendezvous() and therefore must happen
+ * after SMP is fully functional (after SI_SUB_SMP).
+ * - vmm device initialization requires an initialized devfs.
+ */
+DECLARE_MODULE(vmm, vmm_kmod, MAX(SI_SUB_SMP, SI_SUB_DEVFS) + 1, SI_ORDER_ANY);
+MODULE_VERSION(vmm, 1);
+
+static int
devmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t len,
struct vm_object **objp, int nprot)
{