vmm: Move the module load handler to vmm_dev.c

Move the vmm_initialized check out of vm_create() and into the legacy
sysctl handler.  If vmm_initialized is false, /dev/vmmctl will not be
available and so cannot be used to create VMs.

Introduce new MD vmm_modinit() and vmm_modcleanup() routines which
handle MD (de)initialization.

No functional change intended.

Reviewed by:	corvink
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D53421
This commit is contained in:
Mark Johnston
2025-11-04 13:54:27 +00:00
parent 3faad9e260
commit e758074458
5 changed files with 90 additions and 201 deletions
+10 -73
View File
@@ -31,7 +31,6 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/module.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/pcpu.h> #include <sys/pcpu.h>
@@ -189,8 +188,6 @@ struct vm {
#define VMM_CTR4(vcpu, format, p1, p2, p3, p4) \ #define VMM_CTR4(vcpu, format, p1, p2, p3, p4) \
VCPU_CTR4((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3, p4) VCPU_CTR4((vcpu)->vm, (vcpu)->vcpuid, format, p1, p2, p3, p4)
static int vmm_initialized;
static void vmmops_panic(void); static void vmmops_panic(void);
static void static void
@@ -402,8 +399,8 @@ vm_exitinfo_cpuset(struct vcpu *vcpu)
return (&vcpu->exitinfo_cpuset); return (&vcpu->exitinfo_cpuset);
} }
static int int
vmm_init(void) vmm_modinit(void)
{ {
if (!vmm_is_hw_supported()) if (!vmm_is_hw_supported())
return (ENXIO); return (ENXIO);
@@ -431,70 +428,17 @@ vmm_init(void)
return (vmmops_modinit(vmm_ipinum)); return (vmmops_modinit(vmm_ipinum));
} }
static int int
vmm_handler(module_t mod, int what, void *arg) vmm_modcleanup(void)
{ {
int error; vmm_suspend_p = NULL;
vmm_resume_p = NULL;
switch (what) { iommu_cleanup();
case MOD_LOAD: if (vmm_ipinum != IPI_AST)
if (vmm_is_hw_supported()) { lapic_ipi_free(vmm_ipinum);
error = vmmdev_init(); return (vmmops_modcleanup());
if (error != 0)
break;
error = vmm_init();
if (error == 0)
vmm_initialized = 1;
else
(void)vmmdev_cleanup();
} else {
error = ENXIO;
}
break;
case MOD_UNLOAD:
if (vmm_is_hw_supported()) {
error = vmmdev_cleanup();
if (error == 0) {
vmm_suspend_p = NULL;
vmm_resume_p = NULL;
iommu_cleanup();
if (vmm_ipinum != IPI_AST)
lapic_ipi_free(vmm_ipinum);
error = vmmops_modcleanup();
/*
* Something bad happened - prevent new
* VMs from being created
*/
if (error)
vmm_initialized = 0;
}
} else {
error = 0;
}
break;
default:
error = 0;
break;
}
return (error);
} }
static moduledata_t vmm_kmod = {
"vmm",
vmm_handler,
NULL
};
/*
* vmm initialization has the following dependencies:
*
* - VT-x 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 void static void
vm_init(struct vm *vm, bool create) vm_init(struct vm *vm, bool create)
{ {
@@ -579,13 +523,6 @@ vm_create(const char *name, struct vm **retvm)
struct vm *vm; struct vm *vm;
int error; int error;
/*
* If vmm.ko could not be successfully initialized then don't attempt
* to create the virtual machine.
*/
if (!vmm_initialized)
return (ENXIO);
if (name == NULL || strnlen(name, VM_MAX_NAMELEN + 1) == if (name == NULL || strnlen(name, VM_MAX_NAMELEN + 1) ==
VM_MAX_NAMELEN + 1) VM_MAX_NAMELEN + 1)
return (EINVAL); return (EINVAL);
+9 -64
View File
@@ -33,7 +33,6 @@
#include <sys/linker.h> #include <sys/linker.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/pcpu.h> #include <sys/pcpu.h>
#include <sys/proc.h> #include <sys/proc.h>
@@ -138,8 +137,6 @@ struct vm {
struct sx vcpus_init_lock; /* (o) */ struct sx vcpus_init_lock; /* (o) */
}; };
static bool vmm_initialized = false;
static int vm_handle_wfi(struct vcpu *vcpu, static int vm_handle_wfi(struct vcpu *vcpu,
struct vm_exit *vme, bool *retu); struct vm_exit *vme, bool *retu);
@@ -323,11 +320,15 @@ vmm_unsupported_quirk(void)
return (0); return (0);
} }
static int int
vmm_init(void) vmm_modinit(void)
{ {
int error; int error;
error = vmm_unsupported_quirk();
if (error != 0)
return (error);
vm_maxcpu = mp_ncpus; vm_maxcpu = mp_ncpus;
TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu); TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu);
@@ -345,61 +346,12 @@ vmm_init(void)
return (vmmops_modinit(0)); return (vmmops_modinit(0));
} }
static int int
vmm_handler(module_t mod, int what, void *arg) vmm_modcleanup(void)
{ {
int error; return (vmmops_modcleanup());
switch (what) {
case MOD_LOAD:
error = vmm_unsupported_quirk();
if (error != 0)
break;
error = vmmdev_init();
if (error != 0)
break;
error = vmm_init();
if (error == 0)
vmm_initialized = true;
else
(void)vmmdev_cleanup();
break;
case MOD_UNLOAD:
error = vmmdev_cleanup();
if (error == 0 && vmm_initialized) {
error = vmmops_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:
*
* - HYP 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 void static void
vm_init(struct vm *vm, bool create) vm_init(struct vm *vm, bool create)
{ {
@@ -485,13 +437,6 @@ vm_create(const char *name, struct vm **retvm)
struct vm *vm; struct vm *vm;
int error; int error;
/*
* If vmm.ko could not be successfully initialized then don't attempt
* to create the virtual machine.
*/
if (!vmm_initialized)
return (ENXIO);
if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) if (name == NULL || strlen(name) >= VM_MAX_NAMELEN)
return (EINVAL); return (EINVAL);
+63 -2
View File
@@ -14,6 +14,7 @@
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/module.h>
#include <sys/priv.h> #include <sys/priv.h>
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/queue.h> #include <sys/queue.h>
@@ -78,6 +79,8 @@ struct vmmdev_softc {
int flags; int flags;
}; };
static bool vmm_initialized = false;
static SLIST_HEAD(, vmmdev_softc) head; static SLIST_HEAD(, vmmdev_softc) head;
static unsigned pr_allow_flag; static unsigned pr_allow_flag;
@@ -1021,6 +1024,9 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
char *buf; char *buf;
int error, buflen; int error, buflen;
if (!vmm_initialized)
return (ENXIO);
error = vmm_priv_check(req->td->td_ucred); error = vmm_priv_check(req->td->td_ucred);
if (error != 0) if (error != 0)
return (error); return (error);
@@ -1106,7 +1112,7 @@ static struct cdevsw vmmctlsw = {
.d_ioctl = vmmctl_ioctl, .d_ioctl = vmmctl_ioctl,
}; };
int static int
vmmdev_init(void) vmmdev_init(void)
{ {
int error; int error;
@@ -1122,7 +1128,7 @@ vmmdev_init(void)
return (error); return (error);
} }
int static int
vmmdev_cleanup(void) vmmdev_cleanup(void)
{ {
sx_xlock(&vmmdev_mtx); sx_xlock(&vmmdev_mtx);
@@ -1139,6 +1145,61 @@ vmmdev_cleanup(void)
return (0); return (0);
} }
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;
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 static int
devmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t len, devmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t len,
struct vm_object **objp, int nprot) struct vm_object **objp, int nprot)
+3 -2
View File
@@ -18,8 +18,9 @@ struct thread;
struct vm; struct vm;
struct vcpu; struct vcpu;
int vmmdev_init(void); int vmm_modinit(void);
int vmmdev_cleanup(void); int vmm_modcleanup(void);
int vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, int vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd,
caddr_t data, int fflag, struct thread *td); caddr_t data, int fflag, struct thread *td);
+5 -60
View File
@@ -38,7 +38,6 @@
#include <sys/linker.h> #include <sys/linker.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/pcpu.h> #include <sys/pcpu.h>
#include <sys/proc.h> #include <sys/proc.h>
@@ -133,8 +132,6 @@ struct vm {
struct sx vcpus_init_lock; /* (o) */ struct sx vcpus_init_lock; /* (o) */
}; };
static bool vmm_initialized = false;
static MALLOC_DEFINE(M_VMM, "vmm", "vmm"); static MALLOC_DEFINE(M_VMM, "vmm", "vmm");
/* statistics */ /* statistics */
@@ -210,10 +207,9 @@ vm_exitinfo(struct vcpu *vcpu)
return (&vcpu->exitinfo); return (&vcpu->exitinfo);
} }
static int int
vmm_init(void) vmm_modinit(void)
{ {
vm_maxcpu = mp_ncpus; vm_maxcpu = mp_ncpus;
TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu); TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu);
@@ -229,56 +225,12 @@ vmm_init(void)
return (vmmops_modinit()); return (vmmops_modinit());
} }
static int int
vmm_handler(module_t mod, int what, void *arg) vmm_modcleanup(void)
{ {
int error; return (vmmops_modcleanup());
switch (what) {
case MOD_LOAD:
error = vmmdev_init();
if (error != 0)
break;
error = vmm_init();
if (error == 0)
vmm_initialized = true;
else
(void)vmmdev_cleanup();
break;
case MOD_UNLOAD:
error = vmmdev_cleanup();
if (error == 0 && vmm_initialized) {
error = vmmops_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:
*
* - vmm device initialization requires an initialized devfs.
*/
DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_DEVFS + 1, SI_ORDER_ANY);
MODULE_VERSION(vmm, 1);
static void static void
vm_init(struct vm *vm, bool create) vm_init(struct vm *vm, bool create)
{ {
@@ -359,13 +311,6 @@ vm_create(const char *name, struct vm **retvm)
struct vm *vm; struct vm *vm;
int error; int error;
/*
* If vmm.ko could not be successfully initialized then don't attempt
* to create the virtual machine.
*/
if (!vmm_initialized)
return (ENXIO);
if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) if (name == NULL || strlen(name) >= VM_MAX_NAMELEN)
return (EINVAL); return (EINVAL);