git: e758074458df - main - vmm: Move the module load handler to vmm_dev.c

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 04 Nov 2025 14:36:05 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=e758074458df3b61773b7678ff47c4a835365d21

commit e758074458df3b61773b7678ff47c4a835365d21
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-11-04 13:54:27 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-11-04 13:54:27 +0000

    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
---
 sys/amd64/vmm/vmm.c   | 83 +++++++--------------------------------------------
 sys/arm64/vmm/vmm.c   | 73 ++++++--------------------------------------
 sys/dev/vmm/vmm_dev.c | 65 ++++++++++++++++++++++++++++++++++++++--
 sys/dev/vmm/vmm_dev.h |  5 ++--
 sys/riscv/vmm/vmm.c   | 65 ++++------------------------------------
 5 files changed, 90 insertions(+), 201 deletions(-)

diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 615a3c9867dd..627a5a2c5ece 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -31,7 +31,6 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/module.h>
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
 #include <sys/pcpu.h>
@@ -189,8 +188,6 @@ struct vm {
 #define	VMM_CTR4(vcpu, 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
@@ -402,8 +399,8 @@ vm_exitinfo_cpuset(struct vcpu *vcpu)
 	return (&vcpu->exitinfo_cpuset);
 }
 
-static int
-vmm_init(void)
+int
+vmm_modinit(void)
 {
 	if (!vmm_is_hw_supported())
 		return (ENXIO);
@@ -431,70 +428,17 @@ vmm_init(void)
 	return (vmmops_modinit(vmm_ipinum));
 }
 
-static int
-vmm_handler(module_t mod, int what, void *arg)
+int
+vmm_modcleanup(void)
 {
-	int error;
-
-	switch (what) {
-	case MOD_LOAD:
-		if (vmm_is_hw_supported()) {
-			error = vmmdev_init();
-			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);
+	vmm_suspend_p = NULL;
+	vmm_resume_p = NULL;
+	iommu_cleanup();
+	if (vmm_ipinum != IPI_AST)
+		lapic_ipi_free(vmm_ipinum);
+	return (vmmops_modcleanup());
 }
 
-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
 vm_init(struct vm *vm, bool create)
 {
@@ -579,13 +523,6 @@ vm_create(const char *name, struct vm **retvm)
 	struct vm *vm;
 	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) ==
 	    VM_MAX_NAMELEN + 1)
 		return (EINVAL);
diff --git a/sys/arm64/vmm/vmm.c b/sys/arm64/vmm/vmm.c
index e7b2b5d8c360..58f53b34b2cb 100644
--- a/sys/arm64/vmm/vmm.c
+++ b/sys/arm64/vmm/vmm.c
@@ -33,7 +33,6 @@
 #include <sys/linker.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
-#include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/pcpu.h>
 #include <sys/proc.h>
@@ -138,8 +137,6 @@ struct vm {
 	struct sx	vcpus_init_lock;	/* (o) */
 };
 
-static bool vmm_initialized = false;
-
 static int vm_handle_wfi(struct vcpu *vcpu,
 			 struct vm_exit *vme, bool *retu);
 
@@ -323,11 +320,15 @@ vmm_unsupported_quirk(void)
 	return (0);
 }
 
-static int
-vmm_init(void)
+int
+vmm_modinit(void)
 {
 	int error;
 
+	error = vmm_unsupported_quirk();
+	if (error != 0)
+		return (error);
+
 	vm_maxcpu = mp_ncpus;
 	TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu);
 
@@ -345,61 +346,12 @@ vmm_init(void)
 	return (vmmops_modinit(0));
 }
 
-static int
-vmm_handler(module_t mod, int what, void *arg)
+int
+vmm_modcleanup(void)
 {
-	int error;
-
-	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);
+	return (vmmops_modcleanup());
 }
 
-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
 vm_init(struct vm *vm, bool create)
 {
@@ -485,13 +437,6 @@ vm_create(const char *name, struct vm **retvm)
 	struct vm *vm;
 	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)
 		return (EINVAL);
 
diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c
index bd20acac1d2d..08a53bb62a85 100644
--- a/sys/dev/vmm/vmm_dev.c
+++ b/sys/dev/vmm/vmm_dev.c
@@ -14,6 +14,7 @@
 #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>
@@ -78,6 +79,8 @@ struct vmmdev_softc {
 	int		flags;
 };
 
+static bool vmm_initialized = false;
+
 static SLIST_HEAD(, vmmdev_softc) head;
 
 static unsigned pr_allow_flag;
@@ -1021,6 +1024,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);
@@ -1106,7 +1112,7 @@ static struct cdevsw vmmctlsw = {
 	.d_ioctl	= vmmctl_ioctl,
 };
 
-int
+static int
 vmmdev_init(void)
 {
 	int error;
@@ -1122,7 +1128,7 @@ vmmdev_init(void)
 	return (error);
 }
 
-int
+static int
 vmmdev_cleanup(void)
 {
 	sx_xlock(&vmmdev_mtx);
@@ -1139,6 +1145,61 @@ vmmdev_cleanup(void)
 	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
 devmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t len,
     struct vm_object **objp, int nprot)
diff --git a/sys/dev/vmm/vmm_dev.h b/sys/dev/vmm/vmm_dev.h
index 2881a7063565..c691341d4350 100644
--- a/sys/dev/vmm/vmm_dev.h
+++ b/sys/dev/vmm/vmm_dev.h
@@ -18,8 +18,9 @@ struct thread;
 struct vm;
 struct vcpu;
 
-int	vmmdev_init(void);
-int	vmmdev_cleanup(void);
+int	vmm_modinit(void);
+int	vmm_modcleanup(void);
+
 int	vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd,
 	    caddr_t data, int fflag, struct thread *td);
 
diff --git a/sys/riscv/vmm/vmm.c b/sys/riscv/vmm/vmm.c
index a9eb9d144336..f2995b276072 100644
--- a/sys/riscv/vmm/vmm.c
+++ b/sys/riscv/vmm/vmm.c
@@ -38,7 +38,6 @@
 #include <sys/linker.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
-#include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/pcpu.h>
 #include <sys/proc.h>
@@ -133,8 +132,6 @@ struct vm {
 	struct sx	vcpus_init_lock;	/* (o) */
 };
 
-static bool vmm_initialized = false;
-
 static MALLOC_DEFINE(M_VMM, "vmm", "vmm");
 
 /* statistics */
@@ -210,10 +207,9 @@ vm_exitinfo(struct vcpu *vcpu)
 	return (&vcpu->exitinfo);
 }
 
-static int
-vmm_init(void)
+int
+vmm_modinit(void)
 {
-
 	vm_maxcpu = mp_ncpus;
 
 	TUNABLE_INT_FETCH("hw.vmm.maxcpu", &vm_maxcpu);
@@ -229,56 +225,12 @@ vmm_init(void)
 	return (vmmops_modinit());
 }
 
-static int
-vmm_handler(module_t mod, int what, void *arg)
+int
+vmm_modcleanup(void)
 {
-	int error;
-
-	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);
+	return (vmmops_modcleanup());
 }
 
-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
 vm_init(struct vm *vm, bool create)
 {
@@ -359,13 +311,6 @@ vm_create(const char *name, struct vm **retvm)
 	struct vm *vm;
 	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)
 		return (EINVAL);