From 99127fd103624de593c7d1d885387e7d3667d73d Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 5 Nov 2024 01:36:33 +0000 Subject: [PATCH] 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 --- lib/libvmmapi/internal.h | 3 +- lib/libvmmapi/vmmapi.c | 104 +++++++++++++++++++++++++++++---------- lib/libvmmapi/vmmapi.h | 3 ++ 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 #include +#include #include #include #include @@ -50,11 +51,12 @@ #include #include -#include #ifdef WITH_VMMAPI_SNAPSHOT #include #endif +#include + #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);