aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2024-11-05 01:36:33 +0000
committerMark Johnston <markj@FreeBSD.org>2024-11-05 01:40:41 +0000
commit99127fd103624de593c7d1d885387e7d3667d73d (patch)
tree75e7c3f904cca16fea384af135975235e5e22afb
parentebd48f1e52d79ef5d34415d9368c564f3e9bbc08 (diff)
libvmmapi: Use the vmmctl device file to create and destroy VMs
This deprecates the vm_create() and vm_open() interfaces and introduces vm_openf(), which takes flags controlling its behaviour. In particular, it will optionally create a VM first, and it can optionally reinitialize an existing VM. This enables some simplification of existing consumers. Reviewed by: jhb Differential Revision: https://reviews.freebsd.org/D47030
-rw-r--r--lib/libvmmapi/internal.h3
-rw-r--r--lib/libvmmapi/vmmapi.c104
-rw-r--r--lib/libvmmapi/vmmapi.h3
3 files changed, 83 insertions, 27 deletions
diff --git a/lib/libvmmapi/internal.h b/lib/libvmmapi/internal.h
index 42be9ec59770..aa7b1d8e6a93 100644
--- a/lib/libvmmapi/internal.h
+++ b/lib/libvmmapi/internal.h
@@ -16,7 +16,8 @@ enum {
};
struct vmctx {
- int fd;
+ int fd; /* device file descriptor */
+ int ctlfd; /* vmm control descriptor */
struct {
vm_paddr_t base;
vm_size_t size;
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 0cf051567110..5042a1f3914e 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -37,6 +37,7 @@
#include <sys/cpuset.h>
#include <capsicum_helpers.h>
+#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
@@ -50,11 +51,12 @@
#include <vm/vm.h>
#include <machine/vmm.h>
-#include <machine/vmm_dev.h>
#ifdef WITH_VMMAPI_SNAPSHOT
#include <machine/vmm_snapshot.h>
#endif
+#include <dev/vmm/vmm_dev.h>
+
#include "vmmapi.h"
#include "internal.h"
@@ -78,58 +80,104 @@
#define PROT_RW (PROT_READ | PROT_WRITE)
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
-#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
-#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
-
static int
vm_device_open(const char *name)
{
- int fd, len;
- char *vmfile;
+ char devpath[PATH_MAX];
- len = strlen("/dev/vmm/") + strlen(name) + 1;
- vmfile = malloc(len);
- assert(vmfile != NULL);
- snprintf(vmfile, len, "/dev/vmm/%s", name);
+ assert(strlen(name) <= VM_MAX_NAMELEN);
+ (void)snprintf(devpath, sizeof(devpath), "/dev/vmm/%s", name);
+ return (open(devpath, O_RDWR));
+}
- /* Open the device file */
- fd = open(vmfile, O_RDWR, 0);
+static int
+vm_ctl_create(const char *name, int ctlfd)
+{
+ struct vmmctl_vm_create vmc;
- free(vmfile);
- return (fd);
+ memset(&vmc, 0, sizeof(vmc));
+ if (strlcpy(vmc.name, name, sizeof(vmc.name)) >= sizeof(vmc.name)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ return (ioctl(ctlfd, VMMCTL_VM_CREATE, &vmc));
}
int
vm_create(const char *name)
{
+ int error, fd;
+
/* Try to load vmm(4) module before creating a guest. */
- if (modfind("vmm") < 0)
- kldload("vmm");
- return (CREATE(name));
+ if (modfind("vmm") < 0) {
+ error = kldload("vmm");
+ if (error != 0)
+ return (-1);
+ }
+
+ fd = open("/dev/vmmctl", O_RDWR, 0);
+ if (fd < 0)
+ return (fd);
+ error = vm_ctl_create(name, fd);
+ if (error != 0) {
+ error = errno;
+ (void)close(fd);
+ errno = error;
+ return (-1);
+ }
+ (void)close(fd);
+ return (0);
}
struct vmctx *
vm_open(const char *name)
{
+ return (vm_openf(name, 0));
+}
+
+struct vmctx *
+vm_openf(const char *name, int flags)
+{
struct vmctx *vm;
int saved_errno;
+ bool created;
+
+ created = false;
vm = malloc(sizeof(struct vmctx) + strlen(name) + 1);
assert(vm != NULL);
- vm->fd = -1;
+ vm->fd = vm->ctlfd = -1;
vm->memflags = 0;
vm->name = (char *)(vm + 1);
strcpy(vm->name, name);
memset(vm->memsegs, 0, sizeof(vm->memsegs));
- if ((vm->fd = vm_device_open(vm->name)) < 0)
+ if ((vm->ctlfd = open("/dev/vmmctl", O_RDWR, 0)) < 0)
+ goto err;
+
+ vm->fd = vm_device_open(vm->name);
+ if (vm->fd < 0 && errno == ENOENT) {
+ if (flags & VMMAPI_OPEN_CREATE) {
+ if (vm_ctl_create(vm->name, vm->ctlfd) != 0)
+ goto err;
+ vm->fd = vm_device_open(vm->name);
+ created = true;
+ }
+ }
+ if (vm->fd < 0)
+ goto err;
+
+ if (!created && (flags & VMMAPI_OPEN_REINIT) != 0 && vm_reinit(vm) != 0)
goto err;
return (vm);
err:
saved_errno = errno;
- free(vm);
+ if (created)
+ vm_destroy(vm);
+ else
+ vm_close(vm);
errno = saved_errno;
return (NULL);
}
@@ -139,20 +187,24 @@ vm_close(struct vmctx *vm)
{
assert(vm != NULL);
- close(vm->fd);
+ if (vm->fd >= 0)
+ (void)close(vm->fd);
+ if (vm->ctlfd >= 0)
+ (void)close(vm->ctlfd);
free(vm);
}
void
vm_destroy(struct vmctx *vm)
{
- assert(vm != NULL);
+ struct vmmctl_vm_destroy vmd;
- if (vm->fd >= 0)
- close(vm->fd);
- DESTROY(vm->name);
+ memset(&vmd, 0, sizeof(vmd));
+ (void)strlcpy(vmd.name, vm->name, sizeof(vmd.name));
+ if (ioctl(vm->ctlfd, VMMCTL_VM_DESTROY, &vmd) != 0)
+ warn("ioctl(VMMCTL_VM_DESTROY)");
- free(vm);
+ vm_close(vm);
}
struct vcpu *
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index 0ea1d5824271..440064ad13cb 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -117,6 +117,9 @@ int vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
int vm_create(const char *name);
struct vmctx *vm_open(const char *name);
+#define VMMAPI_OPEN_CREATE 0x01 /* create if the VM does not exist */
+#define VMMAPI_OPEN_REINIT 0x02 /* reinitialize the VM if it exists */
+struct vmctx *vm_openf(const char *name, int flags);
void vm_close(struct vmctx *ctx);
void vm_destroy(struct vmctx *ctx);
int vm_limit_rights(struct vmctx *ctx);