View | Details | Raw Unified | Return to bug 213689 | Differences between
and this patch

Collapse All | Expand All

(-)b/lib/libvmmapi/vmmapi.c (-9 / +22 lines)
Lines 77-85 struct vmctx { Link Here
77
	char	*name;
77
	char	*name;
78
};
78
};
79
79
80
#define	CREATE(x)  sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
81
#define	DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
82
83
static int
80
static int
84
vm_device_open(const char *name)
81
vm_device_open(const char *name)
85
{
82
{
Lines 101-108 vm_device_open(const char *name) Link Here
101
int
98
int
102
vm_create(const char *name)
99
vm_create(const char *name)
103
{
100
{
101
	int error, fd;
102
103
	fd = open("/dev/vmmctl", O_RDWR);
104
	if (fd == -1)
105
		return fd;
104
106
105
	return (CREATE((char *)name));
107
	error = ioctl(fd, VMCTL_CREATE, name);
108
	close(fd);
109
	return error;
106
}
110
}
107
111
108
struct vmctx *
112
struct vmctx *
Lines 128-143 err: Link Here
128
	return (NULL);
132
	return (NULL);
129
}
133
}
130
134
131
void
135
int
132
vm_destroy(struct vmctx *vm)
136
vm_destroy(struct vmctx *vm)
133
{
137
{
138
	int fd, error;
139
134
	assert(vm != NULL);
140
	assert(vm != NULL);
141
	fd = open("/dev/vmmctl", O_RDWR);
142
	if (fd == -1)
143
		return fd;
135
144
136
	if (vm->fd >= 0)
145
	error = ioctl(fd, VMCTL_DESTROY, vm->name);
137
		close(vm->fd);
146
	close(fd);
138
	DESTROY(vm->name);
139
147
140
	free(vm);
148
	if (error != -1) {
149
		if (vm->fd >= 0)
150
			close(vm->fd);
151
		free(vm);
152
	}
153
	return error;
141
}
154
}
142
155
143
int
156
int
(-)b/lib/libvmmapi/vmmapi.h (-1 / +1 lines)
Lines 103-109 int vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid, Link Here
103
103
104
int	vm_create(const char *name);
104
int	vm_create(const char *name);
105
struct vmctx *vm_open(const char *name);
105
struct vmctx *vm_open(const char *name);
106
void	vm_destroy(struct vmctx *ctx);
106
int	vm_destroy(struct vmctx *ctx);
107
int	vm_parse_memsize(const char *optarg, size_t *memsize);
107
int	vm_parse_memsize(const char *optarg, size_t *memsize);
108
int	vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
108
int	vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
109
void	*vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len);
109
void	*vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len);
(-)b/sys/amd64/include/vmm_dev.h (+5 lines)
Lines 382-385 enum { Link Here
382
	_IOR('v', IOCNUM_RTC_GETTIME, struct vm_rtc_time)
382
	_IOR('v', IOCNUM_RTC_GETTIME, struct vm_rtc_time)
383
#define	VM_RESTART_INSTRUCTION \
383
#define	VM_RESTART_INSTRUCTION \
384
	_IOW('v', IOCNUM_RESTART_INSTRUCTION, int)
384
	_IOW('v', IOCNUM_RESTART_INSTRUCTION, int)
385
386
#define VMCTL_CREATE \
387
	_IOW('v', 1, char*)
388
#define VMCTL_DESTROY \
389
	_IOW('v', 2, char*)
385
#endif
390
#endif
(-)b/sys/amd64/vmm/vmm_dev.c (-119 / +181 lines)
Lines 36-41 __FBSDID("$FreeBSD$"); Link Here
36
#include <sys/mutex.h>
36
#include <sys/mutex.h>
37
#include <sys/malloc.h>
37
#include <sys/malloc.h>
38
#include <sys/conf.h>
38
#include <sys/conf.h>
39
#include <sys/proc.h>
39
#include <sys/sysctl.h>
40
#include <sys/sysctl.h>
40
#include <sys/libkern.h>
41
#include <sys/libkern.h>
41
#include <sys/ioccom.h>
42
#include <sys/ioccom.h>
Lines 746-804 vmmdev_destroy(void *arg) Link Here
746
	free(sc, M_VMMDEV);
747
	free(sc, M_VMMDEV);
747
}
748
}
748
749
749
static int
750
sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
751
{
752
	int error;
753
	char buf[VM_MAX_NAMELEN];
754
	struct devmem_softc *dsc;
755
	struct vmmdev_softc *sc;
756
	struct cdev *cdev;
757
758
	strlcpy(buf, "beavis", sizeof(buf));
759
	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
760
	if (error != 0 || req->newptr == NULL)
761
		return (error);
762
763
	mtx_lock(&vmmdev_mtx);
764
	sc = vmmdev_lookup(buf);
765
	if (sc == NULL || sc->cdev == NULL) {
766
		mtx_unlock(&vmmdev_mtx);
767
		return (EINVAL);
768
	}
769
770
	/*
771
	 * The 'cdev' will be destroyed asynchronously when 'si_threadcount'
772
	 * goes down to 0 so we should not do it again in the callback.
773
	 *
774
	 * Setting 'sc->cdev' to NULL is also used to indicate that the VM
775
	 * is scheduled for destruction.
776
	 */
777
	cdev = sc->cdev;
778
	sc->cdev = NULL;		
779
	mtx_unlock(&vmmdev_mtx);
780
781
	/*
782
	 * Schedule all cdevs to be destroyed:
783
	 *
784
	 * - any new operations on the 'cdev' will return an error (ENXIO).
785
	 *
786
	 * - when the 'si_threadcount' dwindles down to zero the 'cdev' will
787
	 *   be destroyed and the callback will be invoked in a taskqueue
788
	 *   context.
789
	 *
790
	 * - the 'devmem' cdevs are destroyed before the virtual machine 'cdev'
791
	 */
792
	SLIST_FOREACH(dsc, &sc->devmem, link) {
793
		KASSERT(dsc->cdev != NULL, ("devmem cdev already destroyed"));
794
		destroy_dev_sched_cb(dsc->cdev, devmem_destroy, dsc);
795
	}
796
	destroy_dev_sched_cb(cdev, vmmdev_destroy, sc);
797
	return (0);
798
}
799
SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW,
800
	    NULL, 0, sysctl_vmm_destroy, "A", NULL);
801
802
static struct cdevsw vmmdevsw = {
750
static struct cdevsw vmmdevsw = {
803
	.d_name		= "vmmdev",
751
	.d_name		= "vmmdev",
804
	.d_version	= D_VERSION,
752
	.d_version	= D_VERSION,
Lines 808-875 static struct cdevsw vmmdevsw = { Link Here
808
	.d_write	= vmmdev_rw,
756
	.d_write	= vmmdev_rw,
809
};
757
};
810
758
811
static int
812
sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
813
{
814
	int error;
815
	struct vm *vm;
816
	struct cdev *cdev;
817
	struct vmmdev_softc *sc, *sc2;
818
	char buf[VM_MAX_NAMELEN];
819
820
	strlcpy(buf, "beavis", sizeof(buf));
821
	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
822
	if (error != 0 || req->newptr == NULL)
823
		return (error);
824
825
	mtx_lock(&vmmdev_mtx);
826
	sc = vmmdev_lookup(buf);
827
	mtx_unlock(&vmmdev_mtx);
828
	if (sc != NULL)
829
		return (EEXIST);
830
831
	error = vm_create(buf, &vm);
832
	if (error != 0)
833
		return (error);
834
835
	sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
836
	sc->vm = vm;
837
	SLIST_INIT(&sc->devmem);
838
839
	/*
840
	 * Lookup the name again just in case somebody sneaked in when we
841
	 * dropped the lock.
842
	 */
843
	mtx_lock(&vmmdev_mtx);
844
	sc2 = vmmdev_lookup(buf);
845
	if (sc2 == NULL) {
846
		SLIST_INSERT_HEAD(&head, sc, link);
847
		sc->flags |= VSC_LINKED;
848
	}
849
	mtx_unlock(&vmmdev_mtx);
850
851
	if (sc2 != NULL) {
852
		vmmdev_destroy(sc);
853
		return (EEXIST);
854
	}
855
856
	error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL,
857
			   UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf);
858
	if (error != 0) {
859
		vmmdev_destroy(sc);
860
		return (error);
861
	}
862
863
	mtx_lock(&vmmdev_mtx);
864
	sc->cdev = cdev;
865
	sc->cdev->si_drv1 = sc;
866
	mtx_unlock(&vmmdev_mtx);
867
868
	return (0);
869
}
870
SYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW,
871
	    NULL, 0, sysctl_vmm_create, "A", NULL);
872
873
void
759
void
874
vmmdev_init(void)
760
vmmdev_init(void)
875
{
761
{
Lines 941-962 devmem_create_cdev(const char *vmname, int segid, char *devname) Link Here
941
	struct vmmdev_softc *sc;
827
	struct vmmdev_softc *sc;
942
	struct cdev *cdev;
828
	struct cdev *cdev;
943
	int error;
829
	int error;
830
	uid_t uid;
831
832
	mtx_lock(&vmmdev_mtx);
833
	sc = vmmdev_lookup(vmname);
834
	KASSERT(sc != NULL, ("%s: vm %s softc not found", __func__, vmname));
835
	if (sc->cdev == NULL) {
836
		/* virtual machine is being created or destroyed */
837
		mtx_unlock(&vmmdev_mtx);
838
		return (ENODEV);
839
	}
840
	uid = sc->cdev->si_uid;
841
	mtx_unlock(&vmmdev_mtx);
944
842
945
	error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &devmemsw, NULL,
843
	error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &devmemsw, NULL,
946
	    UID_ROOT, GID_WHEEL, 0600, "vmm.io/%s.%s", vmname, devname);
844
		uid, GID_WHEEL, 0600, "vmm.io/%s.%s", vmname, devname);
947
	if (error)
845
	if (error)
948
		return (error);
846
		return (error);
949
950
	dsc = malloc(sizeof(struct devmem_softc), M_VMMDEV, M_WAITOK | M_ZERO);
847
	dsc = malloc(sizeof(struct devmem_softc), M_VMMDEV, M_WAITOK | M_ZERO);
951
848
849
	/* The lock was released, check again, if the machine is being destroyed */
952
	mtx_lock(&vmmdev_mtx);
850
	mtx_lock(&vmmdev_mtx);
953
	sc = vmmdev_lookup(vmname);
851
	sc = vmmdev_lookup(vmname);
954
	KASSERT(sc != NULL, ("%s: vm %s softc not found", __func__, vmname));
852
	KASSERT(sc != NULL, ("%s: vm %s softc not found", __func__, vmname));
955
	if (sc->cdev == NULL) {
853
	if (sc->cdev == NULL) {
956
		/* virtual machine is being created or destroyed */
957
		mtx_unlock(&vmmdev_mtx);
854
		mtx_unlock(&vmmdev_mtx);
958
		free(dsc, M_VMMDEV);
855
		free(dsc, M_VMMDEV);
959
		destroy_dev_sched_cb(cdev, NULL, 0);
856
		destroy_dev_sched(cdev);
960
		return (ENODEV);
857
		return (ENODEV);
961
	}
858
	}
962
859
Lines 981-983 devmem_destroy(void *arg) Link Here
981
	dsc->cdev = NULL;
878
	dsc->cdev = NULL;
982
	dsc->sc = NULL;
879
	dsc->sc = NULL;
983
}
880
}
881
882
/* ARGSUSED */
883
static int
884
vmmctl_rw(struct cdev *cdev __unused, struct uio *uio __unused, int flags __unused)
885
{
886
	return EOPNOTSUPP;
887
}
888
889
static int
890
vmmctl_create (char *name, uid_t uid)
891
{
892
	int error;
893
	struct vmmdev_softc *sc, *sc2;
894
	struct cdev *cdev;
895
	struct vm *vm;
896
897
	mtx_lock(&vmmdev_mtx);
898
	sc = vmmdev_lookup(name);
899
	mtx_unlock(&vmmdev_mtx);
900
	if (sc != NULL)
901
		return (EEXIST);
902
903
	error = vm_create(name, &vm);
904
	if (error != 0)
905
		return error;
906
907
	sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
908
	sc->vm = vm;
909
	SLIST_INIT(&sc->devmem);
910
911
	/*
912
	 * Lookup the name again just in case somebody sneaked in when we
913
	 * dropped the lock.
914
	 */
915
	mtx_lock(&vmmdev_mtx);
916
	sc2 = vmmdev_lookup(name);
917
	if (sc2 == NULL) {
918
		SLIST_INSERT_HEAD(&head, sc, link);
919
			sc->flags |= VSC_LINKED;
920
	}
921
	mtx_unlock(&vmmdev_mtx);
922
923
	if (sc2 != NULL) {
924
		vmmdev_destroy(sc);
925
		return EEXIST;
926
	}
927
928
	error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL,
929
					   uid, GID_WHEEL, 0600, "vmm/%s", name);
930
	if (error != 0) {
931
		vmmdev_destroy(sc);
932
		return error;
933
	}
934
935
	mtx_lock(&vmmdev_mtx);
936
	sc->cdev = cdev;
937
	sc->cdev->si_drv1 = sc;
938
	mtx_unlock(&vmmdev_mtx);
939
940
	return 0;
941
}
942
943
static int
944
vmmctl_destroy (char *name)
945
{
946
	struct devmem_softc *dsc;
947
	struct vmmdev_softc *sc;
948
	struct cdev *cdev;
949
950
	mtx_lock(&vmmdev_mtx);
951
	sc = vmmdev_lookup(name);
952
	if (sc == NULL || sc->cdev == NULL) {
953
		mtx_unlock(&vmmdev_mtx);
954
		return EINVAL;
955
	}
956
	/*
957
	 * The 'cdev' will be destroyed asynchronously when 'si_threadcount'
958
	 * goes down to 0 so we should not do it again in the callback.
959
	 *
960
	 * Setting 'sc->cdev' to NULL is also used to indicate that the VM
961
	 * is scheduled for destruction.
962
	 */
963
	cdev = sc->cdev;
964
	sc->cdev = NULL;
965
	mtx_unlock(&vmmdev_mtx);
966
967
	SLIST_FOREACH(dsc, &sc->devmem, link) {
968
		KASSERT(dsc->cdev != NULL, ("devmem cdev already destroyed"));
969
		destroy_dev_sched_cb(dsc->cdev, devmem_destroy, dsc);
970
	}
971
	destroy_dev_sched_cb(cdev, vmmdev_destroy, sc);
972
	return 0;
973
}
974
975
/* ARGSUSED */
976
static int
977
vmmctl_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
978
	int flags __unused, struct thread *td)
979
{
980
	int error;
981
	char *name;
982
	int len;
983
984
	error = 0;
985
986
	switch (cmd) {
987
	case VMCTL_CREATE:
988
		name = (char*) data;
989
		len = strnlen (name, VM_MAX_NAMELEN);
990
		if (len == VM_MAX_NAMELEN) {
991
			error = EINVAL;
992
			goto done;
993
		}
994
		printf ("Creating VM with name: %s\n", name);
995
		error = vmmctl_create (name, td->td_ucred->cr_uid);
996
		break;
997
998
	case VMCTL_DESTROY:
999
		name = (char*) data;
1000
		len = strnlen (name, VM_MAX_NAMELEN);
1001
		if (len == VM_MAX_NAMELEN) {
1002
			error = EINVAL;
1003
			goto done;
1004
		}
1005
		printf ("Destroying VM with name: %s\n", (char*)data);
1006
		error = vmmctl_destroy (name);
1007
		break;
1008
1009
	default:
1010
		error = ENOIOCTL;
1011
	}
1012
done:
1013
	/* Make sure that no handler returns a bogus value like ERESTART */
1014
	KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error));
1015
	return (error);
1016
}
1017
1018
static struct cdevsw vmmctl_cdevsw = {
1019
	.d_version =	D_VERSION,
1020
	.d_open =	(d_open_t*) nullop,
1021
	.d_read =	vmmctl_rw,
1022
	.d_write =	vmmctl_rw,
1023
	.d_ioctl = vmmctl_ioctl,
1024
	.d_name =	"vmmctl",
1025
};
1026
1027
static struct cdev *vmmctl_dev;
1028
1029
static void
1030
vmmctl_sysinit(void *p)
1031
{
1032
	vmmctl_dev = make_dev(&vmmctl_cdevsw, 0,
1033
		UID_ROOT, GID_WHEEL, 0660, "vmmctl");
1034
}
1035
SYSINIT(vmmctl_sysinit, SI_SUB_DEVFS, SI_ORDER_ANY, vmmctl_sysinit, NULL);
1036
1037
static void
1038
vmmctl_sysuninit(void *p)
1039
{
1040
	if (vmmctl_dev != NULL) {
1041
		/* destroy_dev() will wait for all references to go away */
1042
		destroy_dev(vmmctl_dev);
1043
	}
1044
}
1045
SYSUNINIT(vmmctl_sysuninit, SI_SUB_DEVFS, SI_ORDER_ANY, vmmctl_sysuninit, NULL);

Return to bug 213689