Index | Thread | Search

From:
Dave Voutila <dv@sisu.io>
Subject:
tests wanted: vmm(4)/vmd(8) fd-ification
To:
tech@openbsd.org
Date:
Mon, 03 Aug 2026 10:36:00 -0400

Download raw body.

Thread
  • Dave Voutila:

    tests wanted: vmm(4)/vmd(8) fd-ification

Calling on vmm(4)/vmd(8) users to give this diff a test please!

This is a major breaking change I'm proposing to land soon. It changes
the vmm(4) design to create a new file type for each VM. When a VM is
created, the caller gets a new file descriptor for using ioctl(2) calls
against that VM.

This fundamentally changes the design from knowing a "magic number"
(today, the vm id) to possessing a capability (the open file
descriptor).

Why do this?

 - Better isolate which process can manipulate a VM. Today it's a hacky
   combination of knowing the magic number and vmm(4) tracking an owning
   PID. The current design scares me.

 - Better scope the vmm(4) API into basically a control plane vs. data
   plane design. A privileged process with an open /dev/vmm special file
   can launch/terminate VMs, but the manipulation of each VM and VCPU is
   done via its own dedicated file.

 - Using files helps simplify the lifecycle management of VMs in the
   kernel by tying their lifetime to a file. vmd(8) processes emulating
   the VM will have their file descriptor closed by the kernel even if
   the process is killed (e.g. via segfault). This simplifies cleanup of
   dead VMs.

Bonus: there's a slight chance this improves perf slightly, but since
that's not the goal I'm not benchmarking. Given a new ioctl(2) path for
the new VM file type, it may reduce contention on the kernel lock.

Note: this is unlike Linux/KVM which uses not only a file per VM, but
one per VCPU. I see no reason for that level of complication at the moment.

I don't expect detailed review yet given the size of this. I plan on
sending separate mails breaking this down into kernel vs. userland (the
userland stuff is a lot of deck chair shuffling) as well as updates to
vmm.4 man page and fstat(1).

To test:

1. build and install new kernel and reboot
2. symlink (recommended) or install headers in /usr/include:
     amd64/vmmvar.h --> sys/arch/amd64/include/vmmvar.h
     dev/vmm/vmm.h --> sys/dev/vmm/vmm.h
     dev/ic/pspvar.h --> sys/dev/ic/pspvar.h
3. build and install vmd(8) and vmctl(8) (if this fails, check your
   headers in /usr/include/ point to the patched ones in the tree)
4. run your existing VMs...you should see no discernable difference in
   behavior.

If things break or behavior changes, please report to me including:

* cpu0 details from dmesg(1)
* details on how the vm is started (/etc/vm.conf contents or vmctl(8)
  args)
* vmd(8) debug output if any (try running vmd in the foreground via
  something like: # $(which vmd) -dvv

** I specifically need help testing SEV-related usage as I have no
commercial grade AMD hardware with all the cool SEV stuff. **

Once I land this I'll no longer lose sleep worrying about the current
design and can turn my attentions to MMIO/instruction emulation needed
for getting to SMP ;)

Thanks!


diff refs/heads/master refs/heads/vmm-fd-jul26
commit - 753d8ebbd61c7c59174b7ab89908a0255c619a28
commit + 66a3ad45782363aca9df3781694198b9774a6eab
blob - cf3afe729cc6dee1d6789ce566d9cfef7d6141e5
blob + 43836fe9639258c08ebaa50ea3a55cccb9d9e6ce
--- regress/sys/arch/amd64/vmm/vcpu.c
+++ regress/sys/arch/amd64/vmm/vcpu.c
@@ -90,11 +90,10 @@ main(int argc, char **argv)
 	struct vm_info_result		*info = NULL, *ours = NULL;
 	struct vm_resetcpu_params	 vresetp;
 	struct vm_run_params		 vrunp;
-	struct vm_terminate_params	 vtp;
 	struct vm_sharemem_params	 vsp;

 	struct vm_mem_range		*vmr;
-	int				 fd, ret = 1;
+	int				 fd, vm_fd = -1, ret = 1;
 	size_t				 i;
 	off_t				 off, reset = 0xFFFFFFF0, stack = 0x800;
 	void				*p;
@@ -120,23 +119,21 @@ main(int argc, char **argv)

 	if (ioctl(fd, VMM_IOC_CREATE, &vcp) == -1)
 		err(1, "VMM_IOC_CREATE");
-	printf("created vm %d named \"%s\"\n", vcp.vcp_id, vcp.vcp_name);
+	printf("created vm fd %d named \"%s\"\n", vcp.vcp_fd, vcp.vcp_name);
+	vm_fd = vcp.vcp_fd;

 	/*
 	 * 2. Check we can create shared memory mappings.
 	 */
 	memset(&vsp, 0, sizeof(vsp));
-	vsp.vsp_nmemranges = vcp.vcp_nmemranges;
-	memcpy(&vsp.vsp_memranges, &vcp.vcp_memranges,
-	    sizeof(vsp.vsp_memranges));
-	vsp.vsp_vm_id = vcp.vcp_id;
+	vsp.vsp_fd = vm_fd;

 	/* Perform the shared mapping. */
-	if (ioctl(fd, VMM_IOC_SHAREMEM, &vsp) == -1)
+	if (ioctl(vm_fd, VMM_IOC_SHAREMEM, &vsp) == -1)
 		err(1, "VMM_IOC_SHAREMEM");
 	printf("created shared memory mappings\n");

-	for (i = 0; i < vsp.vsp_nmemranges; i++)
+	for (i = 0; i < vcp.vcp_nmemranges; i++)
 		vcp.vcp_memranges[i].vmr_va = vsp.vsp_va[i];

 	for (i = 0; i < vcp.vcp_nmemranges; i++) {
@@ -178,8 +175,8 @@ main(int argc, char **argv)
 	}

 	/* We should see our reset vector instructions in the new mappings. */
-	for (i = 0; i < vsp.vsp_nmemranges; i++) {
-		vmr = &vsp.vsp_memranges[i];
+	for (i = 0; i < vcp.vcp_nmemranges; i++) {
+		vmr = &vcp.vcp_memranges[i];
 		p = (void*)vmr->vmr_va;

 		if (i == LOW_MEM) {
@@ -229,43 +226,38 @@ main(int argc, char **argv)
 	}

 	for (i = 0; i * sizeof(*info) < vip.vip_size; i++) {
-		if (info[i].vir_id == vcp.vcp_id) {
+		if (info[i].vir_creator_pid == getpid()) {
 			ours = &info[i];
 			break;
 		}
 	}
 	if (ours == NULL) {
-		warn("failed to find vm %uz", vcp.vcp_id);
+		warn("failed to find vm for pid %d", getpid());
 		goto out;
 	}

-	if (ours->vir_id != vcp.vcp_id) {
-		warnx("expected vm id %uz, got %uz", vcp.vcp_id, ours->vir_id);
-		goto out;
-	}
 	if (strncmp(ours->vir_name, VM_NAME, strlen(VM_NAME)) != 0) {
 		warnx("expected vm name \"%s\", got \"%s\"", VM_NAME,
 		    ours->vir_name);
 		goto out;
 	}
-	printf("found vm %d named \"%s\"\n", vcp.vcp_id, ours->vir_name);
+	printf("found vm for pid %d named \"%s\"\n", getpid(), ours->vir_name);
 	ours = NULL;

 	/*
 	 * 4. Reset our VCPU and initialize register state.
 	 */
 	memset(&vresetp, 0, sizeof(vresetp));
-	vresetp.vrp_vm_id = vcp.vcp_id;
+	vresetp.vrp_fd = vm_fd;
 	vresetp.vrp_vcpu_id = 0;	/* XXX SP */
 	memcpy(&vresetp.vrp_init_state, &vcpu_init_flat16,
 	    sizeof(vcpu_init_flat16));

-	if (ioctl(fd, VMM_IOC_RESETCPU, &vresetp) == -1) {
+	if (ioctl(vm_fd, VMM_IOC_RESETCPU, &vresetp) == -1) {
 		warn("VMM_IOC_RESETCPU");
 		goto out;
 	}
-	printf("reset vcpu %d for vm %d\n", vresetp.vrp_vcpu_id,
-	    vresetp.vrp_vm_id);
+	printf("reset vcpu %d for vm fd %d\n", vresetp.vrp_vcpu_id, vm_fd);

 	/*
 	 * 5. Run the vcpu, expecting an immediate exit for IO assist.
@@ -279,26 +271,20 @@ main(int argc, char **argv)
 	memset(&vrunp, 0, sizeof(vrunp));
 	vrunp.vrp_exit = exit;
 	vrunp.vrp_vcpu_id = 0;		/* XXX SP */
-	vrunp.vrp_vm_id = vcp.vcp_id;
+	vrunp.vrp_fd = vm_fd;
 	vrunp.vrp_irqready = 1;

-	if (ioctl(fd, VMM_IOC_RUN, &vrunp) == -1) {
+	if (ioctl(vm_fd, VMM_IOC_RUN, &vrunp) == -1) {
 		warn("VMM_IOC_RUN");
 		goto out;
 	}

-	if (vrunp.vrp_vm_id != vcp.vcp_id) {
-		warnx("expected vm id %uz, got %uz", vcp.vcp_id,
-		    vrunp.vrp_vm_id);
-		goto out;
-	}
-
 	switch (vrunp.vrp_exit_reason) {
 	case SVM_VMEXIT_IOIO:
 	case VMX_EXIT_IO:
-		printf("vcpu %d on vm %d exited for io assist @ ip = 0x%llx, "
+		printf("vcpu %d on vm fd %d exited for io assist @ ip = 0x%llx, "
 		    "cs.base = 0x%llx, ss.base = 0x%llx, rsp = 0x%llx\n",
-		    vrunp.vrp_vcpu_id, vrunp.vrp_vm_id,
+		    vrunp.vrp_vcpu_id, vm_fd,
 		    vrunp.vrp_exit->vrs.vrs_gprs[VCPU_REGS_RIP],
 		    vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_CS].vsi_base,
 		    vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_SS].vsi_base,
@@ -333,7 +319,7 @@ main(int argc, char **argv)
 	vrunp.vrp_inject.vie_errorcode = 0x11223344;
 	vrunp.vrp_inject.vie_type = VCPU_INJECT_EX;
 	printf("injecting exception 0x%x\n", vrunp.vrp_inject.vie_vector);
-	if (ioctl(fd, VMM_IOC_RUN, &vrunp) == -1) {
+	if (ioctl(vm_fd, VMM_IOC_RUN, &vrunp) == -1) {
 		warn("VMM_IOC_RUN 2");
 		goto out;
 	}
@@ -341,8 +327,8 @@ main(int argc, char **argv)
 	switch (vrunp.vrp_exit_reason) {
 	case SVM_VMEXIT_IOIO:
 	case VMX_EXIT_IO:
-		printf("vcpu %d on vm %d exited for io assist @ ip = 0x%llx, "
-		    "cs.base = 0x%llx\n", vrunp.vrp_vcpu_id, vrunp.vrp_vm_id,
+		printf("vcpu %d on vm fd %d exited for io assist @ ip = 0x%llx, "
+		    "cs.base = 0x%llx\n", vrunp.vrp_vcpu_id, vm_fd,
 		    vrunp.vrp_exit->vrs.vrs_gprs[VCPU_REGS_RIP],
 		    vrunp.vrp_exit->vrs.vrs_sregs[VCPU_REGS_CS].vsi_base);
 		break;
@@ -372,13 +358,13 @@ out:
 		if (i > 0)
 			printf(" ");
 		printf("%02x", *(uint8_t*)
-		    (vsp.vsp_memranges[UPPER_MEM].vmr_va + off + i));
+		    (vcp.vcp_memranges[UPPER_MEM].vmr_va + off + i));
 	}
 	printf("\n--- STACK @ gpa 0x%llx ---\n", stack);
 	for (i=0; i<16; i++) {
 		if (i > 0)
 			printf(" ");
-		printf("%02x", *(uint8_t*)(vsp.vsp_memranges[LOW_MEM].vmr_va
+		printf("%02x", *(uint8_t*)(vcp.vcp_memranges[LOW_MEM].vmr_va
 			+ stack - i - 1));
 	}
 	printf("\n");
@@ -386,13 +372,8 @@ out:
 	/*
 	 * 6. Terminate our VM and clean up.
 	 */
-	memset(&vtp, 0, sizeof(vtp));
-	vtp.vtp_vm_id = vcp.vcp_id;
-	if (ioctl(fd, VMM_IOC_TERM, &vtp) == -1) {
-		warn("VMM_IOC_TERM");
-		ret = 1;
-	} else
-		printf("terminated vm %d\n", vtp.vtp_vm_id);
+	if (vm_fd != -1)
+		close(vm_fd);

 	close(fd);
 	free(info);
blob - 787b65e29e167453c2d5492d5658833d5a75f5af
blob + 1fd7df73f156a0968bbdeff7b7ae7235b1651ae3
--- sys/arch/amd64/amd64/vmm_machdep.c
+++ sys/arch/amd64/amd64/vmm_machdep.c
@@ -68,12 +68,8 @@ void *l1tf_flush_region;
 void vmx_dump_vmcs_field(uint16_t, const char *);
 int vmm_enabled(void);
 void vmm_activate_machdep(struct device *, int);
-int vmmioctl_machdep(dev_t, u_long, caddr_t, int, struct proc *);
 int vmm_quiesce_vmx(void);
-int vm_run(struct vm_run_params *);
-int vm_intr_pending(struct vm_intr_params *);
-int vm_rwregs(struct vm_rwregs_params *, int);
-int vm_rwvmparams(struct vm_rwvmparams_params *, int);
+int vm_intr_pending(struct vm *, struct vm_intr_params *);
 int vcpu_readregs_vmx(struct vcpu *, uint64_t, int, struct vcpu_reg_state *);
 int vcpu_readregs_svm(struct vcpu *, uint64_t, struct vcpu_reg_state *);
 int vcpu_writeregs_vmx(struct vcpu *, uint64_t, int, struct vcpu_reg_state *);
@@ -148,7 +144,6 @@ void vmx_setmsrbw(struct vcpu *, uint32_t);
 void vmx_setmsrbrw(struct vcpu *, uint32_t);
 void svm_set_clean(struct vcpu *, uint32_t);
 void svm_set_dirty(struct vcpu *, uint32_t);
-int svm_get_vmsa_pa(uint32_t, uint32_t, uint64_t *);

 int vmm_gpa_is_valid(struct vcpu *vcpu, paddr_t gpa, size_t obj_size);
 void vmm_init_pvclock(struct vcpu *, paddr_t);
@@ -438,34 +433,6 @@ vmm_activate_machdep(struct device *self, int act)
 	}
 }

-int
-vmmioctl_machdep(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
-{
-	int ret;
-
-	switch (cmd) {
-	case VMM_IOC_INTR:
-		ret = vm_intr_pending((struct vm_intr_params *)data);
-		break;
-	default:
-		DPRINTF("%s: unknown ioctl code 0x%lx\n", __func__, cmd);
-		ret = ENOTTY;
-	}
-
-	return (ret);
-}
-
-int
-pledge_ioctl_vmm_machdep(struct proc *p, long com)
-{
-	switch (com) {
-	case VMM_IOC_INTR:
-		return (0);
-	}
-
-	return (EPERM);
-}
-
 /*
  * vm_intr_pending
  *
@@ -480,22 +447,14 @@ pledge_ioctl_vmm_machdep(struct proc *p, long com)
  *  ENOENT: if the VM/VCPU defined by 'vip' cannot be found
  */
 int
-vm_intr_pending(struct vm_intr_params *vip)
+vm_intr_pending(struct vm *vm, struct vm_intr_params *vip)
 {
-	struct vm *vm;
 	struct vcpu *vcpu;
 #ifdef MULTIPROCESSOR
 	struct cpu_info *ci;
 #endif
-	int error, ret = 0;
+	int ret = 0;

-	/* Find the desired VM */
-	error = vm_find(vip->vip_vm_id, &vm);
-
-	/* Not found? exit. */
-	if (error != 0)
-		return (error);
-
 	vcpu = vm_find_vcpu(vm, vip->vip_vcpu_id);

 	if (vcpu == NULL) {
@@ -511,7 +470,6 @@ vm_intr_pending(struct vm_intr_params *vip)
 #endif

 out:
-	refcnt_rele_wake(&vm->vm_refcnt);
 	return (ret);
 }

@@ -531,19 +489,11 @@ out:
  *  EINVAL: if an error occurred reading the registers of the guest
  */
 int
-vm_rwvmparams(struct vm_rwvmparams_params *vpp, int dir)
+vm_rwvmparams(struct vm *vm, struct vm_rwvmparams_params *vpp, int dir)
 {
-	struct vm *vm;
 	struct vcpu *vcpu;
-	int error, ret = 0;
+	int ret = 0;

-	/* Find the desired VM */
-	error = vm_find(vpp->vpp_vm_id, &vm);
-
-	/* Not found? exit. */
-	if (error != 0)
-		return (error);
-
 	vcpu = vm_find_vcpu(vm, vpp->vpp_vcpu_id);

 	if (vcpu == NULL) {
@@ -565,7 +515,6 @@ vm_rwvmparams(struct vm_rwvmparams_params *vpp, int di
 		}
 	}
 out:
-	refcnt_rele_wake(&vm->vm_refcnt);
 	return (ret);
 }

@@ -587,20 +536,12 @@ out:
  *  EPERM: if the vm cannot be accessed from the calling process
  */
 int
-vm_rwregs(struct vm_rwregs_params *vrwp, int dir)
+vm_rwregs(struct vm *vm, struct vm_rwregs_params *vrwp, int dir)
 {
-	struct vm *vm;
 	struct vcpu *vcpu;
 	struct vcpu_reg_state *vrs = &vrwp->vrwp_regs;
-	int error, ret = 0;
+	int ret = 0;

-	/* Find the desired VM */
-	error = vm_find(vrwp->vrwp_vm_id, &vm);
-
-	/* Not found? exit. */
-	if (error != 0)
-		return (error);
-
 	vcpu = vm_find_vcpu(vm, vrwp->vrwp_vcpu_id);

 	if (vcpu == NULL) {
@@ -623,7 +564,6 @@ vm_rwregs(struct vm_rwregs_params *vrwp, int dir)
 	}
 	rw_exit_write(&vcpu->vc_lock);
 out:
-	refcnt_rele_wake(&vm->vm_refcnt);
 	return (ret);
 }

@@ -3348,20 +3288,12 @@ vcpu_vmx_compute_ctrl(uint64_t ctrlval, uint16_t ctrl,
  *  0: the run loop exited and no help is needed from vmd(8)
  */
 int
-vm_run(struct vm_run_params *vrp)
+vm_run(struct vm *vm, struct vm_run_params *vrp)
 {
-	struct vm *vm;
 	struct vcpu *vcpu;
 	int ret = 0, vcpu_rv = 0;
 	u_int old, next;

-	/*
-	 * Find desired VM
-	 */
-	ret = vm_find(vrp->vrp_vm_id, &vm);
-	if (ret)
-		return (ret);
-
 	vcpu = vm_find_vcpu(vm, vrp->vrp_vcpu_id);
 	if (vcpu == NULL) {
 		ret = ENOENT;
@@ -3419,7 +3351,6 @@ vm_run(struct vm_run_params *vrp)
 out_unlock:
 	rw_exit_write(&vcpu->vc_lock);
 out:
-	refcnt_rele_wake(&vm->vm_refcnt);
 	return (ret);
 }

@@ -7412,13 +7343,13 @@ vcpu_state_decode(u_int state)
  * Return physical address of VMSA for specified VCPU.
  */
 int
-svm_get_vmsa_pa(uint32_t vmid, uint32_t vcpuid, uint64_t *vmsapa)
+svm_get_vmsa_pa(struct proc *p, int fd, uint32_t vcpuid, uint64_t *vmsapa)
 {
 	struct vm	*vm;
 	struct vcpu	*vcpu;
 	int		 error, ret = 0;

-	error = vm_find(vmid, &vm);
+	error = vm_find_file(fd, p, &vm);
 	if (error)
 		return (error);

blob - 25b1618ad1ff6590eb030e9a89729da2c954c9d0
blob + 3f594cb58dcd585f50bd6ba89bf4fd14824d0b4b
--- sys/arch/amd64/include/vmmvar.h
+++ sys/arch/amd64/include/vmmvar.h
@@ -23,6 +23,8 @@

 #ifndef _LOCORE

+struct vm;
+
 #define VMM_HV_SIGNATURE 	"OpenBSDVMM58"

 /* VMX: Basic Exit Reasons */
@@ -477,7 +479,6 @@ struct vm_exit {

 struct vm_intr_params {
 	/* Input parameters to VMM_IOC_INTR */
-	uint32_t		vip_vm_id;
 	uint32_t		vip_vcpu_id;
 	uint16_t		vip_intr;
 };
@@ -495,7 +496,6 @@ struct vm_rwregs_params {
 	 * Input/output parameters to VMM_IOC_READREGS /
 	 * VMM_IOC_WRITEREGS
 	 */
-	uint32_t		vrwp_vm_id;
 	uint32_t		vrwp_vcpu_id;
 	uint64_t		vrwp_mask;
 	struct vcpu_reg_state	vrwp_regs;
@@ -1056,17 +1056,15 @@ void	vmclear_on_cpu(struct cpu_info *);
 int	vmm_probe_machdep(struct device *, void *, void *);
 void	vmm_attach_machdep(struct device *, struct device *, void *);
 void	vmm_activate_machdep(struct device *, int);
-int	vmmioctl_machdep(dev_t, u_long, caddr_t, int, struct proc *);
-int	pledge_ioctl_vmm_machdep(struct proc *, long);
 int	vmm_start(void);
 int	vmm_stop(void);
 int	vm_impl_init(struct vm *, struct proc *);
 void	vm_impl_deinit(struct vm *);
 int	vcpu_init(struct vcpu *, struct vm_create_params *);
 void	vcpu_deinit(struct vcpu *);
-int	vm_rwregs(struct vm_rwregs_params *, int);
+int	vm_rwregs(struct vm *, struct vm_rwregs_params *, int);
 int	vcpu_reset_regs(struct vcpu *, struct vcpu_reg_state *);
-int	svm_get_vmsa_pa(uint32_t, uint32_t, uint64_t *);
+int	svm_get_vmsa_pa(struct proc *, int, uint32_t, uint64_t *);

 #endif /* _KERNEL */

blob - fb64df87384303d04ed6112d3f3866b261bb2899
blob + 47973afbc9688f9acab4991fac557abddef0e63f
--- sys/arch/arm64/include/vmmvar.h
+++ sys/arch/arm64/include/vmmvar.h
@@ -63,7 +63,6 @@ struct vm_exit {

 struct vm_intr_params {
 	/* Input parameters to VMM_IOC_INTR */
-	uint32_t		vip_vm_id;
 	uint32_t		vip_vcpu_id;
 	uint16_t		vip_intr;
 };
@@ -76,7 +75,6 @@ struct vm_rwregs_params {
 	 * Input/output parameters to VMM_IOC_READREGS /
 	 * VMM_IOC_WRITEREGS
 	 */
-	uint32_t		vrwp_vm_id;
 	uint32_t		vrwp_vcpu_id;
 	uint64_t		vrwp_mask;
 	struct vcpu_reg_state	vrwp_regs;
blob - 48c463b28898dddfce5e5a7d77ddc4b1e7c57abb
blob + d6765901c6c7a265a84a2c3e170827e414b0e7a9
--- sys/dev/ic/psp.c
+++ sys/dev/ic/psp.c
@@ -697,13 +697,14 @@ psp_activate(struct psp_softc *sc, struct psp_activate
 }

 int
-psp_encrypt_state(struct psp_softc *sc, struct psp_encrypt_state *ues)
+psp_encrypt_state(struct psp_softc *sc, struct psp_encrypt_state *ues,
+    struct proc *p)
 {
 	struct psp_launch_update_vmsa	luvmsa;
 	uint64_t			vmsa_paddr;
 	int				error;

-	error = svm_get_vmsa_pa(ues->vmid, ues->vcpuid, &vmsa_paddr);
+	error = svm_get_vmsa_pa(p, ues->vmfd, ues->vcpuid, &vmsa_paddr);
 	if (error != 0)
 		return (error);

@@ -922,7 +923,8 @@ pspioctl(dev_t dev, u_long cmd, caddr_t data, int flag
 		    (struct psp_snp_platform_status *)data);
 		break;
 	case PSP_IOC_ENCRYPT_STATE:
-		error = psp_encrypt_state(sc, (struct psp_encrypt_state *)data);
+		error = psp_encrypt_state(sc, (struct psp_encrypt_state *)data,
+		    p);
 		break;
 	default:
 		error = ENOTTY;
blob - d319357e8426770b15f9193dd8ba111f16e90ab5
blob + 2c2f24ade1c35ff21d8b94585da699d94c930e19
--- sys/dev/ic/pspvar.h
+++ sys/dev/ic/pspvar.h
@@ -154,7 +154,7 @@ struct psp_encrypt_state {
 	/* Input parameters state encryption */
 	uint32_t		handle;
 	uint32_t		asid;
-	uint32_t		vmid;
+	int			vmfd;
 	uint32_t		vcpuid;
 } __packed;

blob - 42fc6933911239c956034f4f6c6538fe8486c980
blob + 9da1675a6ed73b9edc6e6e2e17bd89ee0c80b42f
--- sys/dev/vmm/vmm.c
+++ sys/dev/vmm/vmm.c
@@ -18,12 +18,16 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
 #include <sys/pool.h>
 #include <sys/pledge.h>
 #include <sys/proc.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
 #include <sys/signalvar.h>
+#include <sys/stat.h>

 #include <uvm/uvm_extern.h>
 #include <uvm/uvm_aobj.h>
@@ -36,6 +40,13 @@ struct vmm_softc *vmm_softc;
 struct pool vm_pool;
 struct pool vcpu_pool;

+int	vmm_probe(struct device *, void *, void *);
+int	vmm_activate(struct device *, int);
+void	vmm_attach(struct device *, struct device *,  void *);
+int	vmmopen(dev_t, int, int, struct proc *);
+int	vmmclose(dev_t, int, int, struct proc *);
+int	vm_find_file(int, struct proc *, struct vm **);
+
 struct cfdriver vmm_cd = {
 	NULL, "vmm", DV_DULL, CD_SKIPHIBERNATE
 };
@@ -44,6 +55,39 @@ const struct cfattach vmm_ca = {
 	sizeof(struct vmm_softc), vmm_probe, vmm_attach, NULL, vmm_activate
 };

+int	pledge_ioctl_vmm_dev(struct proc *, long);
+int	vmm_dev_enter(void);
+void	vmm_dev_exit(void);
+int	vm_create(struct vm_create_params *, struct proc *, struct vm **);
+size_t	vm_create_check_mem_ranges(struct vm_create_params *);
+int	vm_create_file(struct vm_create_params *, struct proc *, struct vm *);
+int	vm_find_pid(pid_t, struct vm **);
+int	vm_get_info(struct vm_info_params *);
+int	vm_intr_pending(struct vm *, struct vm_intr_params *);
+int	vm_terminate(struct vm_terminate_params *);
+int	vm_resetcpu(struct vm *, struct vm_resetcpu_params *);
+int	vm_rwvmparams(struct vm *, struct vm_rwvmparams_params *, int);
+int	vm_share_mem(struct vm *, struct vm_sharemem_params *, struct proc *);
+void	vm_teardown(struct vm **);
+void	vm_request_stop(struct vm *);
+
+int	vm_read(struct file *, struct uio *, int);
+int	vm_write(struct file *, struct uio *, int);
+int	vm_close(struct file *, struct proc *);
+int	vm_kqfilter(struct file *, struct knote *);
+int	vm_ioctl(struct file *, u_long, caddr_t, struct proc *);
+int	vm_stat(struct file *, struct stat *, struct proc *);
+
+static const struct fileops vmops = {
+	.fo_read	= vm_read,
+	.fo_write	= vm_write,
+	.fo_ioctl	= vm_ioctl,
+	.fo_kqfilter	= vm_kqfilter,
+	.fo_stat	= vm_stat,
+	.fo_close	= vm_close,
+	.fo_seek	= NULL,		/* lseek(2) checks for NULL. */
+};
+
 int
 vmm_probe(struct device *parent, void *match, void *aux)
 {
@@ -154,126 +198,137 @@ vmmclose(dev_t dev, int flag, int mode, struct proc *p
 	return 0;
 }

-/*
- * vm_find
- *
- * Function to find an existing VM by its identifier.
- * Must be called under the global vm_lock.
- *
- * Parameters:
- *  id: The VM identifier.
- *  *res: A pointer to the VM or NULL if not found
- *
- * Return values:
- *  0: if successful
- *  ENOENT: if the VM defined by 'id' cannot be found
- *  EPERM: if the VM cannot be accessed by the current process
- */
 int
-vm_find(uint32_t id, struct vm **res)
+vm_find_file(int fd, struct proc *p, struct vm **res)
 {
-	struct proc *p = curproc;
+	struct filedesc *fdp = p->p_fd;
+	struct file *fp;
+	struct vm *vm = NULL;
+
+	*res = NULL;
+
+	if ((fp = fd_getfile(fdp, fd)) == NULL)
+		return (EBADF);
+
+	if (fp->f_type != DTYPE_VMM) {
+		FRELE(fp, p);
+		return (EINVAL);
+	}
+
+	vm = (struct vm *)fp->f_data;
+	refcnt_take(&vm->vm_refcnt);
+	*res = vm;
+	FRELE(fp, p);
+
+	return (0);
+}
+
+int
+vm_find_pid(pid_t pid, struct vm **res)
+{
 	struct vm *vm;
-	int ret = ENOENT;

 	*res = NULL;

+	if (pid <= 0)
+		return (EINVAL);
+
 	rw_enter_read(&vmm_softc->vm_lock);
 	SLIST_FOREACH(vm, &vmm_softc->vm_list, vm_link) {
-		if (vm->vm_id == id) {
-			/*
-			 * In the pledged VM process, only allow to find
-			 * the VM that is running in the current process.
-			 * The managing vmm parent process can lookup all
-			 * all VMs and is indicated by PLEDGE_PROC.
-			 */
-			if (((p->p_pledge &
-			    (PLEDGE_VMM | PLEDGE_PROC)) == PLEDGE_VMM) &&
-			    (vm->vm_creator_pid != p->p_p->ps_pid))
-				ret = EPERM;
-			else {
-				refcnt_take(&vm->vm_refcnt);
-				*res = vm;
-				ret = 0;
-			}
+		if (vm->vm_creator_pid == pid) {
+			refcnt_take(&vm->vm_refcnt);
+			*res = vm;
 			break;
 		}
 	}
 	rw_exit_read(&vmm_softc->vm_lock);

-	if (ret == EPERM)
-		return (pledge_fail(p, EPERM, PLEDGE_VMM));
-	return (ret);
+	if (*res == NULL)
+		return (ENOENT);
+
+	return (0);
 }

 /*
- * vmmioctl
+ * vmm_dev_enter
  *
- * Main ioctl dispatch routine for /dev/vmm. Parses ioctl type and calls
- * appropriate lower level handler routine. Returns result to ioctl caller.
+ * Acquire a reference to the vmm softc instance, sleeping if it's not
+ * currently active due to power management (i.e. suspend/resume).
  */
 int
-vmmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+vmm_dev_enter(void)
 {
 	int ret;

-	KERNEL_UNLOCK();
-
 	ret = rw_enter(&vmm_softc->sc_slock, RW_READ | RW_INTR);
 	if (ret != 0)
-		goto out;
+		return (ret);
 	while (vmm_softc->sc_status != VMM_ACTIVE) {
 		ret = rwsleep_nsec(&vmm_softc->sc_status, &vmm_softc->sc_slock,
 		    PWAIT | PCATCH, "vmmresume", INFSLP);
 		if (ret != 0) {
 			rw_exit(&vmm_softc->sc_slock);
-			goto out;
+			return (ret);
 		}
 	}
 	refcnt_take(&vmm_softc->sc_refcnt);
 	rw_exit(&vmm_softc->sc_slock);
+	return (0);
+}

+/*
+ * vmm_dev_exit
+ *
+ * Release a reference to the vmm softc, waking any waiters.
+ */
+void
+vmm_dev_exit(void)
+{
+	refcnt_rele_wake(&vmm_softc->sc_refcnt);
+}
+
+/*
+ * vmmioctl
+ *
+ * Main ioctl dispatch for vmm(4) providing global operations for
+ * creating, terminating, and inspecting virtual machines.
+ */
+int
+vmmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+	struct vm *vm = NULL;
+	int ret = ENOTTY;
+
+	KERNEL_UNLOCK();
+
+	ret = vmm_dev_enter();
+	if (ret != 0)
+		goto out;
+
 	switch (cmd) {
 	case VMM_IOC_CREATE:
-		if ((ret = vmm_start()) != 0) {
+		ret = vmm_start();
+		if (ret) {
 			vmm_stop();
 			break;
 		}
-		ret = vm_create((struct vm_create_params *)data, p);
+		ret = vm_create((struct vm_create_params *)data, p, &vm);
+		if (ret)
+			break;
+		ret = vm_create_file((struct vm_create_params *)data, p, vm);
 		break;
-	case VMM_IOC_RUN:
-		ret = vm_run((struct vm_run_params *)data);
-		break;
 	case VMM_IOC_INFO:
 		ret = vm_get_info((struct vm_info_params *)data);
 		break;
 	case VMM_IOC_TERM:
 		ret = vm_terminate((struct vm_terminate_params *)data);
 		break;
-	case VMM_IOC_RESETCPU:
-		ret = vm_resetcpu((struct vm_resetcpu_params *)data);
-		break;
-	case VMM_IOC_READREGS:
-		ret = vm_rwregs((struct vm_rwregs_params *)data, 0);
-		break;
-	case VMM_IOC_WRITEREGS:
-		ret = vm_rwregs((struct vm_rwregs_params *)data, 1);
-		break;
-	case VMM_IOC_READVMPARAMS:
-		ret = vm_rwvmparams((struct vm_rwvmparams_params *)data, 0);
-		break;
-	case VMM_IOC_WRITEVMPARAMS:
-		ret = vm_rwvmparams((struct vm_rwvmparams_params *)data, 1);
-		break;
-	case VMM_IOC_SHAREMEM:
-		ret = vm_share_mem((struct vm_sharemem_params *)data, p);
-		break;
 	default:
-		ret = vmmioctl_machdep(dev, cmd, data, flag, p);
+		ret = ENOTTY;
 		break;
 	}

-	refcnt_rele_wake(&vmm_softc->sc_refcnt);
+	vmm_dev_exit();
 out:
 	KERNEL_LOCK();

@@ -281,39 +336,6 @@ out:
 }

 /*
- * pledge_ioctl_vmm
- *
- * Restrict the allowed ioctls in a pledged process context.
- * Is called from pledge_ioctl().
- */
-int
-pledge_ioctl_vmm(struct proc *p, long com)
-{
-	switch (com) {
-	case VMM_IOC_CREATE:
-	case VMM_IOC_INFO:
-	case VMM_IOC_SHAREMEM:
-		/* The "parent" process in vmd forks and manages VMs */
-		if (p->p_pledge & PLEDGE_PROC)
-			return (0);
-		break;
-	case VMM_IOC_TERM:
-		/* XXX VM processes should only terminate themselves */
-	case VMM_IOC_RUN:
-	case VMM_IOC_RESETCPU:
-	case VMM_IOC_READREGS:
-	case VMM_IOC_WRITEREGS:
-	case VMM_IOC_READVMPARAMS:
-	case VMM_IOC_WRITEVMPARAMS:
-		return (0);
-	default:
-		return pledge_ioctl_vmm_machdep(p, com);
-	}
-
-	return (EPERM);
-}
-
-/*
  * vm_find_vcpu
  *
  * Lookup VMM VCPU by ID number
@@ -353,7 +375,7 @@ vm_find_vcpu(struct vm *vm, uint32_t id)
  *  various other errors from vcpu_init/vm_impl_init
  */
 int
-vm_create(struct vm_create_params *vcp, struct proc *p)
+vm_create(struct vm_create_params *vcp, struct proc *p, struct vm **out)
 {
 	int i, ret = EINVAL;
 	size_t memsize;
@@ -363,6 +385,8 @@ vm_create(struct vm_create_params *vcp, struct proc *p
 	struct vm_mem_range *vmr;
 	unsigned int uvmflags = 0;

+	*out = NULL;
+
 	memsize = vm_create_check_mem_ranges(vcp);
 	if (memsize == 0)
 		return (EINVAL);
@@ -474,7 +498,6 @@ vm_create(struct vm_create_params *vcp, struct proc *p
 	rw_enter_write(&vmm_softc->vm_lock);
 	vmm_softc->vm_idx++;
 	vm->vm_id = vmm_softc->vm_idx;
-	vcp->vcp_id = vm->vm_id;

 	refcnt_init(&vm->vm_refcnt);
 	SLIST_INSERT_HEAD(&vmm_softc->vm_list, vm, vm_link);
@@ -484,6 +507,7 @@ vm_create(struct vm_create_params *vcp, struct proc *p
 	memcpy(vcp->vcp_memranges, vm->vm_memranges,
 	    vcp->vcp_nmemranges * sizeof(vcp->vcp_memranges[0]));

+	*out = vm;
 	return (0);

 err:
@@ -639,10 +663,12 @@ vm_get_info(struct vm_info_params *vip)
 	struct vm *vm;
 	struct vcpu *vcpu;
 	int i = 0, j;
-	size_t need, vm_ct;
+	size_t alloc, need, vm_ct;

 	rw_enter_read(&vmm_softc->vm_lock);
-	vm_ct = vmm_softc->vm_ct;
+	vm_ct = 0;
+	SLIST_FOREACH(vm, &vmm_softc->vm_list, vm_link)
+		vm_ct++;
 	rw_exit_read(&vmm_softc->vm_lock);

 	need = vm_ct * sizeof(struct vm_info_result);
@@ -652,14 +678,19 @@ vm_get_info(struct vm_info_params *vip)
 		return (0);
 	}

-	out = malloc(need, M_DEVBUF, M_NOWAIT|M_ZERO);
+	if (vm_ct == 0) {
+		vip->vip_info_ct = 0;
+		vip->vip_size = 0;
+		return (0);
+	}
+
+	alloc = need;
+	out = malloc(alloc, M_DEVBUF, M_NOWAIT|M_ZERO);
 	if (out == NULL) {
 		vip->vip_info_ct = 0;
 		return (ENOMEM);
 	}

-	vip->vip_info_ct = vm_ct;
-
 	rw_enter_read(&vmm_softc->vm_lock);
 	SLIST_FOREACH(vm, &vmm_softc->vm_list, vm_link) {
 		refcnt_take(&vm->vm_refcnt);
@@ -668,7 +699,6 @@ vm_get_info(struct vm_info_params *vip)
 		out[i].vir_used_size =
 		    pmap_resident_count(vm->vm_pmap) * PAGE_SIZE;
 		out[i].vir_ncpus = vm->vm_vcpu_ct;
-		out[i].vir_id = vm->vm_id;
 		out[i].vir_creator_pid = vm->vm_creator_pid;
 		strlcpy(out[i].vir_name, vm->vm_name, VMM_MAX_NAME_LEN);

@@ -678,7 +708,7 @@ vm_get_info(struct vm_info_params *vip)
 			    vc_vcpu_link) {
 				if (vcpu->vc_id == j)
 					out[i].vir_vcpu_state[j] =
-					    vcpu->vc_state;
+					    atomic_load_int(&vcpu->vc_state);
 			}
 		}

@@ -688,75 +718,91 @@ vm_get_info(struct vm_info_params *vip)
 			break;	/* Truncate to keep within bounds of 'out'. */
 	}
 	rw_exit_read(&vmm_softc->vm_lock);
+	vip->vip_info_ct = i;
+	need = i * sizeof(struct vm_info_result);
+	vip->vip_size = need;

 	if (copyout(out, vip->vip_info, need) == EFAULT) {
-		free(out, M_DEVBUF, need);
+		free(out, M_DEVBUF, alloc);
 		return (EFAULT);
 	}

-	free(out, M_DEVBUF, need);
+	free(out, M_DEVBUF, alloc);
 	return (0);
 }

-/*
- * vm_terminate
- *
- * Terminates the VM indicated by 'vtp'.
- *
- * Parameters:
- *  vtp: structure defining the VM to terminate
- *
- * Return values:
- *  0: the VM was terminated
- *  !0: the VM could not be located
- */
+void
+vm_request_stop(struct vm *vm)
+{
+	struct vcpu *vcpu;
+	u_int old;
+#ifdef MULTIPROCESSOR
+	struct cpu_info *ci;
+#endif
+
+	SLIST_FOREACH(vcpu, &vm->vm_vcpu_list, vc_vcpu_link) {
+		do {
+			old = atomic_load_int(&vcpu->vc_state);
+			if (old == VCPU_STATE_REQTERM ||
+			    old == VCPU_STATE_TERMINATED)
+				break;
+		} while (atomic_cas_uint(&vcpu->vc_state, old,
+		    VCPU_STATE_REQTERM) != old);
+
+#ifdef MULTIPROCESSOR
+		/*
+		 * If this vCPU is currently running in guest mode, nudge the
+		 * host CPU so it exits promptly and observes REQTERM.
+		 */
+		if (old != VCPU_STATE_TERMINATED) {
+			ci = READ_ONCE(vcpu->vc_curcpu);
+			if (ci != NULL)
+				x86_send_ipi(ci, X86_IPI_NOP);
+		}
+#endif
+	}
+}
+
 int
 vm_terminate(struct vm_terminate_params *vtp)
 {
 	struct vm *vm;
-	int error, nvcpu, vm_id;
+	int error, relock;

+	relock = _kernel_lock_held();
+	if (relock)
+		KERNEL_UNLOCK();
+
+	error = vm_find_pid(vtp->vtp_creator_pid, &vm);
+	if (error != 0)
+		goto out;
+
+	/* Only proceed through remove once. */
+	if (atomic_cas_uint(&vm->vm_dying, VMM_VM_ALIVE, VMM_VM_DYING) !=
+	    VMM_VM_ALIVE) {
+		/*
+		 * Already terminating; kick again in case the caller is retrying
+		 * while a VCPU is still running.
+		 */
+		vm_request_stop(vm);
+		refcnt_rele_wake(&vm->vm_refcnt);
+		error = EBUSY;
+		goto out;
+	}
+
 	/*
-	 * Find desired VM
+	 * Request VCPU exit. Teardown is deferred to vm_close() so TERM only
+	 * initiates termination and does not wait for VM file references.
 	 */
-	error = vm_find(vtp->vtp_vm_id, &vm);
-	if (error)
-		return (error);
+	vm_request_stop(vm);
+	refcnt_rele_wake(&vm->vm_refcnt);

-	/* Only proceed through remove and teardown once. */
-	if (atomic_cas_uint(&vm->vm_dying, 0, 1) == 1) {
-		refcnt_rele_wake(&vm->vm_refcnt);
-		return (EBUSY);
-	}
+	error = 0;
+out:
+	if (relock)
+		KERNEL_LOCK();

-	/* Pop the vm out of the global vm list. */
-	rw_enter_write(&vmm_softc->vm_lock);
-	SLIST_REMOVE(&vmm_softc->vm_list, vm, vm, vm_link);
-	rw_exit_write(&vmm_softc->vm_lock);
-
-	/* Drop the vm_list's reference to the vm. */
-	if (refcnt_rele(&vm->vm_refcnt))
-		panic("%s: vm %d(%p) vm_list refcnt drop was the last",
-		    __func__, vm->vm_id, vm);
-
-	/* Wait for our reference (taken from vm_find) is the last active. */
-	refcnt_finalize(&vm->vm_refcnt, __func__);
-
-	vm_id = vm->vm_id;
-	nvcpu = vm->vm_vcpu_ct;
-
-	vm_teardown(&vm);
-
-	if (vm_id > 0) {
-		rw_enter_write(&vmm_softc->vm_lock);
-		vmm_softc->vm_ct--;
-		vmm_softc->vcpu_ct -= nvcpu;
-		if (vmm_softc->vm_ct < 1)
-			vmm_stop();
-		rw_exit_write(&vmm_softc->vm_lock);
-	}
-
-	return (0);
+	return (error);
 }

 /*
@@ -774,27 +820,16 @@ vm_terminate(struct vm_terminate_params *vtp)
  *  EIO if the indicated VCPU failed to reset
  */
 int
-vm_resetcpu(struct vm_resetcpu_params *vrp)
+vm_resetcpu(struct vm *vm, struct vm_resetcpu_params *vrp)
 {
-	struct vm *vm;
 	struct vcpu *vcpu;
-	int error, ret = 0;
+	int ret = 0;

-	/* Find the desired VM */
-	error = vm_find(vrp->vrp_vm_id, &vm);
-
-	/* Not found? exit. */
-	if (error != 0) {
-		DPRINTF("%s: vm id %u not found\n", __func__,
-		    vrp->vrp_vm_id);
-		return (error);
-	}
-
 	vcpu = vm_find_vcpu(vm, vrp->vrp_vcpu_id);

 	if (vcpu == NULL) {
-		DPRINTF("%s: vcpu id %u of vm %u not found\n", __func__,
-		    vrp->vrp_vcpu_id, vrp->vrp_vm_id);
+		DPRINTF("%s: vcpu id %u not found\n", __func__,
+		    vrp->vrp_vcpu_id);
 		ret = ENOENT;
 		goto out;
 	}
@@ -813,8 +848,6 @@ vm_resetcpu(struct vm_resetcpu_params *vrp)
 	}
 	rw_exit_write(&vcpu->vc_lock);
 out:
-	refcnt_rele_wake(&vm->vm_refcnt);
-
 	return (ret);
 }

@@ -838,7 +871,7 @@ vcpu_must_stop(struct vcpu *vcpu)
 {
 	struct proc *p = curproc;

-	if (vcpu->vc_state == VCPU_STATE_REQTERM)
+	if (atomic_load_int(&vcpu->vc_state) == VCPU_STATE_REQTERM)
 		return (1);
 	if (SIGPENDING(p) != 0)
 		return (1);
@@ -856,58 +889,26 @@ vcpu_must_stop(struct vcpu *vcpu)
  *  other errno on uvm_map or uvm_map_immutable failures
  */
 int
-vm_share_mem(struct vm_sharemem_params *vsp, struct proc *p)
+vm_share_mem(struct vm *vm, struct vm_sharemem_params *vsp, struct proc *p)
 {
 	int ret = EINVAL, unmap = 0;
-	size_t i, failed_uao = 0, n;
-	struct vm *vm;
-	struct vm_mem_range *src, *dst;
+	size_t i, failed_uao = 0;
+	struct vm_mem_range *vmr;
 	struct uvm_object *uao;
 	unsigned int uvmflags;

-	ret = vm_find(vsp->vsp_vm_id, &vm);
-	if (ret)
-		return (ret);
-
-	/* Check we have the expected number of ranges. */
-	if (vm->vm_nmemranges != vsp->vsp_nmemranges)
-		goto out;
-	n = vm->vm_nmemranges;
-
-	/* Check their types, sizes, and gpa's (implying page alignment). */
-	for (i = 0; i < n; i++) {
-		src = &vm->vm_memranges[i];
-		dst = &vsp->vsp_memranges[i];
-
-		/*
-		 * The vm memranges were already checked during creation, so
-		 * compare to them to confirm validity of mapping request.
-		 */
-		if (src->vmr_type != dst->vmr_type)
-			goto out;
-		if (src->vmr_gpa != dst->vmr_gpa)
-			goto out;
-		if (src->vmr_size != dst->vmr_size)
-			goto out;
-
-		/* The virtual addresses will be chosen by uvm_map(). */
-		if (vsp->vsp_va[i] != 0)
-			goto out;
-	}
-
 	/* Share each UVM aobj with the calling process. */
 	uvmflags = UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
 	    MAP_INHERIT_NONE, MADV_NORMAL, UVM_FLAG_CONCEAL);
-	for (i = 0; i < n; i++) {
-		dst = &vsp->vsp_memranges[i];
-		if (dst->vmr_type == VM_MEM_MMIO)
+	for (i = 0; i < vm->vm_nmemranges; i++) {
+		vmr = &vm->vm_memranges[i];
+		if (vmr->vmr_type == VM_MEM_MMIO)
 			continue;

 		uao = vm->vm_memory_slot[i];
 		KASSERT(uao != NULL);
-
 		ret = uvm_map(&p->p_p->ps_vmspace->vm_map, &vsp->vsp_va[i],
-		    dst->vmr_size, uao, 0, 0, uvmflags);
+		    vmr->vmr_size, uao, 0, 0, uvmflags);
 		if (ret) {
 			printf("%s: uvm_map failed: %d\n", __func__, ret);
 			unmap = (i > 0) ? 1 : 0;
@@ -917,7 +918,7 @@ vm_share_mem(struct vm_sharemem_params *vsp, struct pr
 		uao_reference(uao);	/* Add a reference for the process. */

 		ret = uvm_map_immutable(&p->p_p->ps_vmspace->vm_map,
-		    vsp->vsp_va[i], vsp->vsp_va[i] + dst->vmr_size, 1);
+		    vsp->vsp_va[i], vsp->vsp_va[i] + vmr->vmr_size, 1);
 		if (ret) {
 			printf("%s: uvm_map_immutable failed: %d\n",
 			    __func__, ret);
@@ -931,11 +932,223 @@ out:
 	if (unmap) {
 		/* Unmap mapped aobjs, which drops the process's reference. */
 		for (i = 0; i < failed_uao; i++) {
-			dst = &vsp->vsp_memranges[i];
+			vmr = &vm->vm_memranges[i];
 			uvm_unmap(&p->p_p->ps_vmspace->vm_map,
-			    vsp->vsp_va[i], vsp->vsp_va[i] + dst->vmr_size);
+			    vsp->vsp_va[i], vsp->vsp_va[i] + vmr->vmr_size);
 		}
 	}
+	return (ret);
+}
+
+int
+vm_create_file(struct vm_create_params *vcp, struct proc *p, struct vm *vm)
+{
+	int fd = -1, ret = 0;
+	struct file *fp = NULL;
+	struct filedesc *fdp = p->p_fd;
+
+	fdplock(fdp);
+
+	ret = falloc(p, &fp, &fd);
+	if (ret)
+		goto err;
+
+	fp->f_flag = FREAD | FWRITE;
+	fp->f_type = DTYPE_VMM;
+	fp->f_data = vm;
+	fp->f_ops = &vmops;
+
+	fdinsert(fdp, fd, 0, fp);
+	vcp->vcp_fd = fd;
+
+	/* Take a reference for the file descriptor. */
+	refcnt_take(&vm->vm_refcnt);
+	FRELE(fp, p);
+err:
+	fdpunlock(fdp);
+
+	return (ret);
+}
+
+int
+vm_read(struct file *fp, struct uio *uio, int fflags)
+{
+	return (ENXIO);
+}
+
+int
+vm_write(struct file *fp, struct uio *uio, int fflags)
+{
+	return (ENXIO);
+}
+
+int
+vm_kqfilter(struct file *fp, struct knote *kn)
+{
+	return (EINVAL);
+}
+
+/*
+ * vm_ioctl
+ *
+ * Dispatcher for all virtual machine operations for the vm referenced
+ * by the file fp.
+ */
+int
+vm_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p)
+{
+	struct vm *vm = (struct vm *)fp->f_data;
+	int ret = 0;
+
+	if (vm == NULL)
+		return (ENXIO);
+
+	KERNEL_ASSERT_UNLOCKED();
+
+	refcnt_take(&vm->vm_refcnt);
+	ret = vmm_dev_enter();
+	if (ret != 0)
+		goto out;
+
+	if (atomic_load_int(&vm->vm_dying) != VMM_VM_ALIVE) {
+		if (cmd == VMM_IOC_RUN) {
+			((struct vm_run_params *)data)->vrp_exit_reason =
+			    VM_EXIT_TERMINATED;
+			ret = 0;
+		} else {
+			ret = EBUSY;
+		}
+		goto out_active;
+	}
+
+	switch (cmd) {
+	case VMM_IOC_RUN:
+		ret = vm_run(vm, (struct vm_run_params *)data);
+		break;
+	case VMM_IOC_RESETCPU:
+		ret = vm_resetcpu(vm, (struct vm_resetcpu_params *)data);
+		break;
+	case VMM_IOC_READREGS:
+		ret = vm_rwregs(vm, (struct vm_rwregs_params *)data, 0);
+		break;
+	case VMM_IOC_WRITEREGS:
+		ret = vm_rwregs(vm, (struct vm_rwregs_params *)data, 1);
+		break;
+	case VMM_IOC_READVMPARAMS:
+		ret = vm_rwvmparams(vm, (struct vm_rwvmparams_params *)data, 0);
+		break;
+	case VMM_IOC_WRITEVMPARAMS:
+		ret = vm_rwvmparams(vm, (struct vm_rwvmparams_params *)data, 1);
+		break;
+	case VMM_IOC_SHAREMEM:
+		ret = vm_share_mem(vm, (struct vm_sharemem_params *)data, p);
+		break;
+	case VMM_IOC_INTR:
+		ret = vm_intr_pending(vm, (struct vm_intr_params *)data);
+		break;
+	default:
+		ret = ENOTTY;
+		break;
+	}
+
+out_active:
+	vmm_dev_exit();
+out:
 	refcnt_rele_wake(&vm->vm_refcnt);
 	return (ret);
 }
+
+int
+vm_close(struct file *fp, struct proc *p)
+{
+	int nvcpu, vm_id;
+	int teardown_owner = 0;
+	int remove_from_list = 0;
+	int account = 0;
+	int relock;
+	struct vm *vm = (struct vm *)fp->f_data;
+
+	if (vm == NULL)
+		return (0);
+
+	/*
+	 * vm_close is called from multiple contexts within the kernel,
+	 * inside and outside of vmm(4). Some callers hold the kernel lock.
+	 * Since vmm(4) operates without the kernel lock, we need to
+	 * unlock and relock before return.
+	 */
+	relock = _kernel_lock_held();
+	if (relock)
+		KERNEL_UNLOCK();
+
+	fp->f_ops = NULL;
+	fp->f_data = NULL;
+
+	/* No active teardown owner; this close owns teardown now. */
+	if (atomic_cas_uint(&vm->vm_dying, VMM_VM_ALIVE, VMM_VM_TEARDOWN) ==
+	    VMM_VM_ALIVE) {
+		teardown_owner = 1;
+		remove_from_list = 1;
+		account = 1;
+		vm_request_stop(vm);
+	} else if (atomic_cas_uint(&vm->vm_dying, VMM_VM_DYING,
+	    VMM_VM_TEARDOWN) == VMM_VM_DYING) {
+		teardown_owner = 1;
+		remove_from_list = 1;
+		account = 1;
+		vm_request_stop(vm);
+	}
+	if (!teardown_owner) {
+		refcnt_rele_wake(&vm->vm_refcnt);
+		if (relock)
+			KERNEL_LOCK();
+		return (0);
+	}
+
+	if (remove_from_list) {
+		/* Remove the vm from the global vm list. */
+		rw_enter_write(&vmm_softc->vm_lock);
+		SLIST_REMOVE(&vmm_softc->vm_list, vm, vm, vm_link);
+		rw_exit_write(&vmm_softc->vm_lock);
+
+		/* Drop the vm_list's reference. */
+		if (refcnt_rele(&vm->vm_refcnt))
+			panic("%s: vm refcnt is 0 (%p)", __func__, vm);
+	}
+
+	/* Wait for all VM references, including this close's, to drain. */
+	refcnt_finalize(&vm->vm_refcnt, __func__);
+
+	vm_id = vm->vm_id;
+	nvcpu = vm->vm_vcpu_ct;
+	vm_teardown(&vm);
+
+	if (account && vm_id > 0) {
+		rw_enter_write(&vmm_softc->vm_lock);
+		vmm_softc->vm_ct--;
+		vmm_softc->vcpu_ct -= nvcpu;
+		if (vmm_softc->vm_ct < 1)
+			vmm_stop();
+		rw_exit_write(&vmm_softc->vm_lock);
+	}
+
+	if (relock)
+		KERNEL_LOCK();
+	return (0);
+}
+
+int
+vm_stat(struct file *fp, struct stat *st, struct proc *p)
+{
+	struct vm *vm = (struct vm *)fp->f_data;
+
+	if (vm == NULL)
+		return (0);
+
+	memset(st, 0, sizeof(*st));
+	st->st_mode = S_IFCHR;
+	st->st_blksize = PAGE_SIZE;
+	st->st_blocks = pmap_resident_count(vm->vm_pmap);
+
+	return (0);
+}
blob - f50c974f67d68da56fc7fc3469eb27348b2c249e
blob + 6b5195b0fbb3ea71a7d7953c68c943c04a5475de
--- sys/dev/vmm/vmm.h
+++ sys/dev/vmm/vmm.h
@@ -54,11 +54,10 @@ struct vm_create_params {
 	char			vcp_name[VMM_MAX_NAME_LEN];
 	int			vcp_sev;
 	int			vcp_seves;
-
-        /* Output parameter from VMM_IOC_CREATE */
-        uint32_t		vcp_id;
-        uint32_t		vcp_poscbit;
-        uint32_t		vcp_asid[VMM_MAX_VCPUS];
+	/* Output parameters from VMM_IOC_CREATE */
+	uint32_t		vcp_poscbit;
+	uint32_t		vcp_asid[VMM_MAX_VCPUS];
+	int			vcp_fd;
 };

 struct vm_info_result {
@@ -68,7 +67,6 @@ struct vm_info_result {
 	size_t		vir_ncpus;
 	uint8_t		vir_vcpu_state[VMM_MAX_VCPUS_PER_VM];
 	pid_t		vir_creator_pid;
-	uint32_t	vir_id;
 	char		vir_name[VMM_MAX_NAME_LEN];
 };

@@ -83,29 +81,22 @@ struct vm_info_params {

 struct vm_terminate_params {
 	/* Input parameters to VMM_IOC_TERM */
-	uint32_t		vtp_vm_id;
+	pid_t			vtp_creator_pid;
 };

 struct vm_resetcpu_params {
 	/* Input parameters to VMM_IOC_RESETCPU */
-	uint32_t		vrp_vm_id;
 	uint32_t		vrp_vcpu_id;
 	struct vcpu_reg_state	vrp_init_state;
 };

 struct vm_sharemem_params {
-	/* Input parameters to VMM_IOC_SHAREMEM */
-	uint32_t		vsp_vm_id;
-	size_t			vsp_nmemranges;
-	struct vm_mem_range	vsp_memranges[VMM_MAX_MEM_RANGES];
-
 	/* Output parameters from VMM_IOC_SHAREMEM */
 	vaddr_t			vsp_va[VMM_MAX_MEM_RANGES];
 };

 struct vm_run_params {
 	/* Input parameters to VMM_IOC_RUN */
-	uint32_t	vrp_vm_id;
 	uint32_t	vrp_vcpu_id;
 	struct vcpu_inject_event	vrp_inject;
 	uint8_t		vrp_intr_pending;	/* Additional intrs pending? */
@@ -125,7 +116,6 @@ struct vm_run_params {

 struct vm_rwvmparams_params {
 	/* Input parameters to VMM_IOC_READVMPARAMS/VMM_IOC_WRITEVMPARAMS */
-	uint32_t		vpp_vm_id;
 	uint32_t		vpp_vcpu_id;
 	uint32_t		vpp_mask;
 	paddr_t			vpp_pvclock_system_gpa;
@@ -163,6 +153,10 @@ enum {
 	VCPU_STATE_UNKNOWN,
 };

+#define VMM_VM_ALIVE		0U
+#define VMM_VM_DYING		1U
+#define VMM_VM_TEARDOWN		2U
+
 /*
  * Virtual Machine
  *
@@ -187,7 +181,7 @@ struct vm {

 	char			 vm_name[VMM_MAX_NAME_LEN];
 	struct refcnt		 vm_refcnt;		/* [a] */
-	unsigned int		 vm_dying;		/* [a] */
+	unsigned int		 vm_dying;		/* [a] VMM_VM_* */

 	struct vcpu_head	 vm_vcpu_list;		/* [v] */
 	uint32_t		 vm_vcpu_ct;		/* [v] */
@@ -244,25 +238,11 @@ extern struct pool vcpu_pool;
 extern struct cfdriver vmm_cd;
 extern const struct cfattach vmm_ca;

-int vmm_probe(struct device *, void *, void *);
-int vmm_activate(struct device *, int);
-void vmm_attach(struct device *, struct device *,  void *);
-int vmmopen(dev_t, int, int, struct proc *);
-int vmmclose(dev_t, int, int, struct proc *);
-int vm_find(uint32_t, struct vm **);
-int vmmioctl_machdep(dev_t, u_long, caddr_t, int, struct proc *);
-int pledge_ioctl_vmm(struct proc *, long);
+int vm_find_file(int, struct proc *, struct vm **);
 struct vcpu *vm_find_vcpu(struct vm *, uint32_t);
-int vm_create(struct vm_create_params *, struct proc *);
-size_t vm_create_check_mem_ranges(struct vm_create_params *);
-void vm_teardown(struct vm **);
-int vm_get_info(struct vm_info_params *);
-int vm_terminate(struct vm_terminate_params *);
-int vm_resetcpu(struct vm_resetcpu_params *);
-int vm_rwvmparams(struct vm_rwvmparams_params *, int);
+int vm_rwvmparams(struct vm *, struct vm_rwvmparams_params *, int);
 int vcpu_must_stop(struct vcpu *);
-int vm_share_mem(struct vm_sharemem_params *, struct proc *);
-int vm_run(struct vm_run_params *);
+int vm_run(struct vm *, struct vm_run_params *);

 #ifdef VMM_DEBUG
 void dump_vcpu(struct vcpu *);
blob - a891eecd1182383629cb4923bee2e879a840c447
blob + e5c5dbf15ab0262e080ad902b5713cb02dceb9e1
--- sys/kern/kern_pledge.c
+++ sys/kern/kern_pledge.c
@@ -75,6 +75,7 @@
 #include "vmm.h"
 #include "psp.h"
 #include <machine/conf.h>
+#include <dev/vmm/vmm.h>
 #endif

 #include "drm.h"
@@ -1348,12 +1349,30 @@ pledge_ioctl(struct proc *p, long com, struct file *fp

 #if NVMM > 0
 	if ((pledge & PLEDGE_VMM)) {
+		if (fp->f_type == DTYPE_VMM) {
+			switch (com) {
+			case VMM_IOC_RUN:
+			case VMM_IOC_RESETCPU:
+			case VMM_IOC_READREGS:
+			case VMM_IOC_WRITEREGS:
+			case VMM_IOC_READVMPARAMS:
+			case VMM_IOC_WRITEVMPARAMS:
+			case VMM_IOC_SHAREMEM:
+			case VMM_IOC_INTR:
+				return (0);
+			default:
+				break;
+			}
+		}
 		if (fp->f_type == DTYPE_VNODE &&
 		    vp->v_type == VCHR &&
 		    cdevsw[major(vp->v_rdev)].d_open == vmmopen) {
-			error = pledge_ioctl_vmm(p, com);
-			if (error == 0)
-				return 0;
+			switch (com) {
+			case VMM_IOC_CREATE:
+			case VMM_IOC_INFO:
+			case VMM_IOC_TERM:
+				return (0);
+			}
 		}
 	}
 #endif
blob - 25c8267ae5d1761a3c872157d68507d1d4be1e9c
blob + dfec6d00cb98178ba3ca5155c121f57f9bfa17a6
--- sys/kern/uipc_usrreq.c
+++ sys/kern/uipc_usrreq.c
@@ -1293,8 +1293,8 @@ morespace:
 		if (error)
 			goto fail;

-		/* kqueue descriptors cannot be copied */
-		if (fp->f_type == DTYPE_KQUEUE) {
+		/* kqueue and vmm descriptors cannot be copied */
+		if (fp->f_type == DTYPE_KQUEUE || fp->f_type == DTYPE_VMM) {
 			error = EINVAL;
 			goto fail;
 		}
blob - b29b43122a4755a18c9b0b0cd3733566f09dda5b
blob + 7aa3c1cedbc827cce93b3abdd611d82ee89ce81f
--- sys/sys/file.h
+++ sys/sys/file.h
@@ -46,6 +46,7 @@
 #define	DTYPE_KQUEUE	4	/* event queue */
 #define	DTYPE_DMABUF	5	/* DMA buffer (for DRM) */
 #define	DTYPE_SYNC	6	/* sync file (for DRM) */
+#define	DTYPE_VMM	7	/* vmm(4) virtual machine */

 #ifdef _KERNEL
 struct proc;
blob - 3379671505b1ffe9f7ef66c32fc8e57113730a0d
blob + dcf07d38bde5c7062a4ad614e7ce9777cf3819d1
--- sys/sys/pledge.h
+++ sys/sys/pledge.h
@@ -128,7 +128,7 @@ int	pledge_sockopt(struct proc *p, int set, int level,
 int	pledge_socket(struct proc *p, int domain, unsigned int state);
 int	pledge_ioctl(struct proc *p, long com, struct file *);
 int	pledge_ioctl_drm(struct proc *p, long com, dev_t device);
-int	pledge_ioctl_vmm(struct proc *p, long com);
+int	pledge_ioctl_vmm_dev(struct proc *p, long com);
 int	pledge_ioctl_psp(struct proc *p, long com);
 int	pledge_flock(struct proc *p);
 int	pledge_fcntl(struct proc *p, int cmd);
blob - bbafef0e084b639c6c7c47d67188b1d52988191b
blob + 6c8446643d730bf88e3271f586732e7d90e8131b
--- usr.bin/fstat/fstat.c
+++ usr.bin/fstat/fstat.c
@@ -127,6 +127,7 @@ void print_inet6_details(struct kinfo_file *);
 void print_sock_details(struct kinfo_file *);
 void socktrans(struct kinfo_file *);
 void vtrans(struct kinfo_file *);
+void vmmtrans(struct kinfo_file *);
 const char *inet6_addrstr(struct in6_addr *);
 int signame_to_signum(char *);
 void hide(void *p);
@@ -414,6 +415,10 @@ fstat_dofile(struct kinfo_file *kf)
 		if (checkfile == 0)
 			kqueuetrans(kf);
 		break;
+	case DTYPE_VMM:
+		if (checkfile == 0)
+			vmmtrans(kf);
+		break;
 	default:
 		if (vflg) {
 			warnx("unknown file type %d for file %d of pid %ld",
@@ -525,6 +530,18 @@ vtrans(struct kinfo_file *kf)
 }

 void
+vmmtrans(struct kinfo_file *kf)
+{
+	PREFIX(kf->fd_fd);
+
+	printf(" ");
+
+	printf("vmm ");
+	hide((void *)(uintptr_t)kf->f_data);
+	putchar('\n');
+}
+
+void
 pipetrans(struct kinfo_file *kf)
 {
 	void *maxaddr;
blob - b05fb152b254d31155d1d75cf3603dbe69be4306
blob + 26b77db4c52b83ab25bb4f750efd30b087ceb1e0
--- usr.sbin/vmd/arm64_vm.c
+++ usr.sbin/vmd/arm64_vm.c
@@ -104,13 +104,13 @@ intr_ack(struct vmd_vm *vm)
 }

 void
-vcpu_assert_irq(uint32_t vm_id, uint32_t vcpu_id, int irq)
+vcpu_assert_irq(int fd, uint32_t vcpu_id, int irq)
 {
 	fatalx("%s: unimplemented", __func__);
 }

 void
-vcpu_deassert_irq(uint32_t vm_id, uint32_t vcpu_id, int irq)
+vcpu_deassert_irq(int fd, uint32_t vcpu_id, int irq)
 {
 	fatalx("%s: unimplemented", __func__);
 }
blob - 09907635f0690399c4aa7ab2d804baf372df97b3
blob + 25fd0cbcf5f345041e659da67afa09e7857b7aee
--- usr.sbin/vmd/dhcp.c
+++ usr.sbin/vmd/dhcp.c
@@ -139,7 +139,7 @@ dhcp_request(struct virtio_dev *dev, char *buf, size_t

 	if (vionet->pxeboot) {
 		strlcpy(resp.file, "auto_install", sizeof resp.file);
-		vm = vm_getbyid(dev->vmm_id);
+		vm = vm_getbyvmid(dev->vm_id);
 		if (vm && res_hnok(vm->vm_params.vmc_name))
 			hostname = vm->vm_params.vmc_name;
 	}
blob - 00b0945da33e131f897f18a0fb692cc660f97114
blob + 469dc82f6eb439b97f7cce5baa38015199572673
--- usr.sbin/vmd/i8253.c
+++ usr.sbin/vmd/i8253.c
@@ -73,29 +73,29 @@ i8253_pipe_dispatch(int fd, short event, void *arg)
  * Initialize the emulated i8253 PIT.
  *
  * Parameters:
- *  vm_id: vmm(4)-assigned ID of the VM
+ *  vm_fd: file descriptor of the VM
  */
 void
-i8253_init(uint32_t vm_id)
+i8253_init(int vm_fd)
 {
 	memset(&i8253_channel, 0, sizeof(struct i8253_channel));
 	clock_gettime(CLOCK_MONOTONIC, &i8253_channel[0].ts);
 	i8253_channel[0].start = 0xFFFF;
 	i8253_channel[0].mode = TIMER_INTTC;
 	i8253_channel[0].last_r = 1;
-	i8253_channel[0].vm_id = vm_id;
+	i8253_channel[0].vm_fd = vm_fd;
 	i8253_channel[0].state = 0;

 	i8253_channel[1].start = 0xFFFF;
 	i8253_channel[1].mode = TIMER_INTTC;
 	i8253_channel[1].last_r = 1;
-	i8253_channel[1].vm_id = vm_id;
+	i8253_channel[1].vm_fd = vm_fd;
 	i8253_channel[1].state = 0;

 	i8253_channel[2].start = 0xFFFF;
 	i8253_channel[2].mode = TIMER_INTTC;
 	i8253_channel[2].last_r = 1;
-	i8253_channel[2].vm_id = vm_id;
+	i8253_channel[2].vm_fd = vm_fd;
 	i8253_channel[2].state = 0;

 	evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]);
@@ -370,7 +370,7 @@ i8253_fire(int fd, short type, void *arg)
 	struct timeval tv;
 	struct i8253_channel *ctr = (struct i8253_channel *)arg;

-	vcpu_assert_irq(ctr->vm_id, 0, 0);
+	vcpu_assert_irq(ctr->vm_fd, 0, 0);

 	if (ctr->mode != TIMER_INTTC) {
 		timerclear(&tv);
blob - c938c42d4cb9030011b009928ba8e2df5483da37
blob + cd173ac300a3532eab1ee5c45cd9aa4fde3d6b29
--- usr.sbin/vmd/i8253.h
+++ usr.sbin/vmd/i8253.h
@@ -39,12 +39,12 @@ struct i8253_channel {
 	uint8_t mode;		/* counter mode */
 	uint8_t rbs;		/* channel is in readback status mode */
 	struct event timer;	/* timer event for this counter */
-	uint32_t vm_id;		/* owning VM id */
+	int vm_fd;		/* owning VM fd */
 	int in_use;		/* denotes if this counter was ever used */
 	uint8_t state;		/* 0 if channel is counting, 1 if fired */
 };

-void i8253_init(uint32_t);
+void i8253_init(int);
 void i8253_reset(uint8_t);
 void i8253_fire(int, short, void *);
 uint8_t vcpu_exit_i8253(struct vm_run_params *);
blob - 0105cfae4292ce1fd50e82c93cdc45a569acc46c
blob + 39b3c9d9d41c86acf2687801a5a0d7b5dc996b59
--- usr.sbin/vmd/mc146818.c
+++ usr.sbin/vmd/mc146818.c
@@ -50,7 +50,7 @@ struct mc146818 {
 	time_t now;
 	uint8_t idx;
 	uint8_t regs[NVRAM_SIZE];
-	uint32_t vm_id;
+	int vm_fd;
 	struct event sec;
 	struct timeval sec_tv;
 	struct event per;
@@ -158,12 +158,12 @@ rtc_fireper(int fd, short type, void *arg)
  * Initializes the emulated RTC/NVRAM
  *
  * Parameters:
- *  vm_id: VM ID to which this RTC belongs
+ *  vm_fd: vm file descriptor to which this RTC belongs
  *  memlo: size of memory in bytes between 16MB .. 4GB
  *  memhi: size of memory in bytes after 4GB
  */
 void
-mc146818_init(uint32_t vm_id, uint64_t memlo, uint64_t memhi)
+mc146818_init(int vm_fd, uint64_t memlo, uint64_t memhi)
 {
 	memset(&rtc, 0, sizeof(rtc));
 	time(&rtc.now);
@@ -182,7 +182,7 @@ mc146818_init(uint32_t vm_id, uint64_t memlo, uint64_t
 	rtc.regs[NVRAM_SMP_COUNT] = 0;

 	rtc_updateregs();
-	rtc.vm_id = vm_id;
+	rtc.vm_fd = vm_fd;

 	timerclear(&rtc.sec_tv);
 	rtc.sec_tv.tv_sec = 1;
@@ -192,7 +192,7 @@ mc146818_init(uint32_t vm_id, uint64_t memlo, uint64_t
 	evtimer_set(&rtc.sec, rtc_fire1, NULL);
 	evtimer_add(&rtc.sec, &rtc.sec_tv);

-	evtimer_set(&rtc.per, rtc_fireper, (void *)(intptr_t)rtc.vm_id);
+	evtimer_set(&rtc.per, rtc_fireper, (void *)(intptr_t)rtc.vm_fd);

 	vm_pipe_init(&dev_pipe, mc146818_pipe_dispatch);
 	event_add(&dev_pipe.read_ev, NULL);
blob - e7cef801303643a57cb905e1698a8dae3b7f5a9b
blob + 64118764de1e79e6aa3dcdf9964819819a03217c
--- usr.sbin/vmd/mc146818.h
+++ usr.sbin/vmd/mc146818.h
@@ -15,7 +15,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */

-void mc146818_init(uint32_t, uint64_t, uint64_t);
+void mc146818_init(int, uint64_t, uint64_t);
 uint8_t vcpu_exit_mc146818(struct vm_run_params *vrp);
 void mc146818_stop(void);
 void mc146818_start(void);
blob - 97970e2155b0890e1914d923d8bcedc1e5dc93ab
blob + 01164b93dffc9ab87897b9c5be6b1b6c57970127
--- usr.sbin/vmd/ns8250.c
+++ usr.sbin/vmd/ns8250.c
@@ -36,7 +36,7 @@ struct ns8250_dev com1_dev;
 static struct vm_dev_pipe dev_pipe;

 static void com_rcv_event(int, short, void *);
-static void com_rcv(struct ns8250_dev *, uint32_t, uint32_t);
+static void com_rcv(struct ns8250_dev *, uint32_t);

 /*
  * ns8250_pipe_dispatch
@@ -78,12 +78,12 @@ ratelimit(int fd, short type, void *arg)
 	com1_dev.regs.iir |= IIR_TXRDY;
 	com1_dev.regs.iir &= ~IIR_NOPEND;

-	vcpu_assert_irq(com1_dev.vmid, 0, com1_dev.irq);
+	vcpu_assert_irq(com1_dev.vm_fd, 0, com1_dev.irq);
 	mutex_unlock(&com1_dev.mutex);
 }

 void
-ns8250_init(int fd, uint32_t vmid)
+ns8250_init(int fd, int vm_fd)
 {
 	int ret;

@@ -95,9 +95,9 @@ ns8250_init(int fd, uint32_t vmid)
 	}

 	com1_dev.fd = fd;
+	com1_dev.vm_fd = vm_fd;
 	com1_dev.irq = 4;
 	com1_dev.portid = NS8250_COM1;
-	com1_dev.vmid = vmid;
 	com1_dev.byte_out = 0;
 	com1_dev.regs.divlo = 1;
 	com1_dev.baudrate = 115200;
@@ -118,7 +118,7 @@ ns8250_init(int fd, uint32_t vmid)
 	com1_dev.pause_ct = (com1_dev.baudrate / 8) / 1000 * 10;

 	event_set(&com1_dev.event, com1_dev.fd, EV_READ | EV_PERSIST,
-	    com_rcv_event, (void *)(intptr_t)vmid);
+	    com_rcv_event, (void *)(intptr_t)vm_fd);

 	/*
 	 * Whenever fd is writable implies that the pty slave is connected.
@@ -126,7 +126,7 @@ ns8250_init(int fd, uint32_t vmid)
 	 * be reached.
 	 */
 	event_set(&com1_dev.wake, com1_dev.fd, EV_WRITE,
-	    com_rcv_event, (void *)(intptr_t)vmid);
+	    com_rcv_event, (void *)(intptr_t)vm_fd);
 	event_add(&com1_dev.wake, NULL);

 	/* Rate limiter for simulating baud rate */
@@ -150,12 +150,12 @@ com_rcv_event(int fd, short kind, void *arg)
 	}

 	if ((com1_dev.regs.lsr & LSR_RXRDY) == 0)
-		com_rcv(&com1_dev, (uintptr_t)arg, 0);
+		com_rcv(&com1_dev, 0);

 	/* If pending interrupt, inject */
 	if ((com1_dev.regs.iir & IIR_NOPEND) == 0) {
 		/* XXX: vcpu_id */
-		vcpu_assert_irq((uintptr_t)arg, 0, com1_dev.irq);
+		vcpu_assert_irq(com1_dev.vm_fd, 0, com1_dev.irq);
 	}

 	mutex_unlock(&com1_dev.mutex);
@@ -192,7 +192,7 @@ com_rcv_handle_break(struct ns8250_dev *com, uint8_t c
  * Must be called with the mutex of the com device acquired
  */
 static void
-com_rcv(struct ns8250_dev *com, uint32_t vm_id, uint32_t vcpu_id)
+com_rcv(struct ns8250_dev *com, uint32_t vcpu_id)
 {
 	char buf[2];
 	ssize_t sz;
@@ -245,7 +245,7 @@ com_rcv(struct ns8250_dev *com, uint32_t vm_id, uint32
  *  interrupt to inject, or 0xFF if nothing to inject
  */
 uint8_t
-vcpu_process_com_data(struct vm_exit *vei, uint32_t vm_id, uint32_t vcpu_id)
+vcpu_process_com_data(struct vm_exit *vei, uint32_t vcpu_id)
 {
 	/*
 	 * vei_dir == VEI_DIR_OUT : out instruction
@@ -612,8 +612,7 @@ vcpu_exit_com(struct vm_run_params *vrp)
 		vcpu_process_com_scr(vei);
 		break;
 	case COM1_DATA:
-		intr = vcpu_process_com_data(vei, vrp->vrp_vm_id,
-		    vrp->vrp_vcpu_id);
+		intr = vcpu_process_com_data(vei, vrp->vrp_vcpu_id);
 		break;
 	}

blob - 7ff4f524d92f1a89eee796b01e3049a1e026db7f
blob + e4ec36d1da494536b71086930de0d4df6386e772
--- usr.sbin/vmd/ns8250.h
+++ usr.sbin/vmd/ns8250.h
@@ -68,16 +68,16 @@ struct ns8250_dev {
 	struct timeval rate_tv;
 	enum ns8250_portid portid;
 	int fd;
+	int vm_fd;
 	int irq;
-	uint32_t vmid;
 	uint64_t byte_out;
 	uint32_t baudrate;
 	uint32_t pause_ct;
 };

-void ns8250_init(int, uint32_t);
+void ns8250_init(int, int);
 uint8_t vcpu_exit_com(struct vm_run_params *);
-uint8_t vcpu_process_com_data(struct vm_exit *, uint32_t, uint32_t);
+uint8_t vcpu_process_com_data(struct vm_exit *, uint32_t);
 void vcpu_process_com_lcr(struct vm_exit *);
 void vcpu_process_com_lsr(struct vm_exit *);
 void vcpu_process_com_ier(struct vm_exit *);
blob - b60f51711dbb30d2ab9d5f917607c77d3dee28eb
blob + e24c794037233838424b137df11ae5d212157262
--- usr.sbin/vmd/psp.c
+++ usr.sbin/vmd/psp.c
@@ -174,15 +174,14 @@ psp_launch_update(uint32_t handle, vaddr_t v, size_t l
  * log it for now.
  */
 int
-psp_encrypt_state(uint32_t handle, uint32_t asid, uint32_t vmid,
-    uint32_t vcpuid)
+psp_encrypt_state(uint32_t handle, uint32_t asid, int vmfd, uint32_t vcpuid)
 {
 	struct psp_encrypt_state es;

 	memset(&es, 0, sizeof(es));
 	es.handle = handle;
 	es.asid = asid;
-	es.vmid = vmid;
+	es.vmfd = vmfd;
 	es.vcpuid = vcpuid;

 	if (ioctl(env->vmd_psp_fd, PSP_IOC_ENCRYPT_STATE, &es) < 0) {
blob - 0fc14a3ce218bfbf85417191c40c6456e204ce89
blob + 57b428a8a12a478e166033d4435345ade089eb21
--- usr.sbin/vmd/sev.c
+++ usr.sbin/vmd/sev.c
@@ -208,7 +208,7 @@ sev_encrypt_state(struct vmd_vm *vm, int vcpu_id)
 		return (0);

 	if (psp_encrypt_state(vm->vm_sev_handle, vm->vm_sev_asid[vcpu_id],
-	    vm->vm_vmmid, vcpu_id)) {
+	    vm->vm_fd, vcpu_id)) {
 		log_warnx("%s: failed to encrypt state: 0x%x 0x%x 0x%0x 0x%0x",
 		    __func__, vm->vm_sev_handle, vm->vm_sev_asid[vcpu_id],
 		    vm->vm_vmid, vcpu_id);
blob - a51e55569cffab27f65c6a0bf276a8a26bb83656
blob + 231eedcab8b80ced86f3a8d67da700b62fa4081e
--- usr.sbin/vmd/vioblk.c
+++ usr.sbin/vmd/vioblk.c
@@ -61,7 +61,7 @@ disk_type(enum vm_disk_fmt type)
 }

 __dead void
-vioblk_main(int fd, int fd_vmm)
+vioblk_main(int fd, int vm_fd)
 {
 	struct virtio_dev	 dev;
 	struct vioblk_dev	*vioblk = NULL;
@@ -99,9 +99,9 @@ vioblk_main(int fd, int fd_vmm)
 	vioblk = &dev.vioblk;

 	log_debug("%s: got viblk dev. num disk fds = %d, sync fd = %d, "
-	    "async fd = %d, capacity = %lld seg_max = %u, vmm fd = %d",
+	    "async fd = %d, capacity = %lld seg_max = %u, vm fd = %d",
 	    __func__, vioblk->ndisk_fd, dev.sync_fd, dev.async_fd,
-	    vioblk->capacity, vioblk->seg_max, fd_vmm);
+	    vioblk->capacity, vioblk->seg_max, vm_fd);

 	/* Receive our vm information from the vm process. */
 	memset(&vm, 0, sizeof(vm));
@@ -117,7 +117,7 @@ vioblk_main(int fd, int fd_vmm)
 	log_procinit("vm/%s/vioblk%d", vm.vm_params.vmc_name, vioblk->idx);

 	/* Now that we have our vm information, we can remap memory. */
-	ret = remap_guest_mem(&vm, fd_vmm);
+	ret = remap_guest_mem(&vm, vm_fd);
 	if (ret) {
 		log_warnx("failed to remap guest memory");
 		goto fail;
@@ -126,7 +126,7 @@ vioblk_main(int fd, int fd_vmm)
 	/*
 	 * We no longer need /dev/vmm access.
 	 */
-	close_fd(fd_vmm);
+	close_fd(vm_fd);
 	if (pledge("stdio", NULL) == -1)
 		fatal("pledge2");

blob - 0aca5b3bb002be577220bcee76b90bd73093f7f7
blob + a5b1e03d1452b0df9f58a5d3c48465ff62c9161e
--- usr.sbin/vmd/vionet.c
+++ usr.sbin/vmd/vionet.c
@@ -105,7 +105,7 @@ pthread_rwlock_t lock = NULL;		/* Guards device config
 int rx_enabled = 0;	/* 1: we expect to read the tap, 0: wait for notify. */

 __dead void
-vionet_main(int fd, int fd_vmm)
+vionet_main(int fd, int vm_fd)
 {
 	struct virtio_dev	 dev;
 	struct vionet_dev	*vionet = NULL;
@@ -141,8 +141,8 @@ vionet_main(int fd, int fd_vmm)
 	vionet = &dev.vionet;

 	log_debug("%s: got vionet dev. tap fd = %d, syncfd = %d, asyncfd = %d"
-	    ", vmm fd = %d", __func__, vionet->data_fd, dev.sync_fd,
-	    dev.async_fd, fd_vmm);
+	    ", vm fd = %d", __func__, vionet->data_fd, dev.sync_fd,
+	    dev.async_fd, vm_fd);

 	/* Receive our vm information from the vm process. */
 	memset(&vm, 0, sizeof(vm));
@@ -157,7 +157,7 @@ vionet_main(int fd, int fd_vmm)
 	log_procinit("vm/%s/vionet%d", vm.vm_params.vmc_name, vionet->idx);

 	/* Now that we have our vm information, we can remap memory. */
-	ret = remap_guest_mem(&vm, fd_vmm);
+	ret = remap_guest_mem(&vm, vm_fd);
 	if (ret) {
 		fatal("%s: failed to remap", __func__);
 		goto fail;
@@ -166,7 +166,7 @@ vionet_main(int fd, int fd_vmm)
 	/*
 	 * We no longer need /dev/vmm access.
 	 */
-	close_fd(fd_vmm);
+	close_fd(vm_fd);
 	if (pledge("stdio", NULL) == -1)
 		fatal("pledge2");

blob - 2e55cb935ded5c0a77cb1876842f650cc0f835d0
blob + cf3ee48e066c343f5dc62ad17b644450fc1edff6
--- usr.sbin/vmd/vioscsi.c
+++ usr.sbin/vmd/vioscsi.c
@@ -57,7 +57,7 @@ static uint32_t vioscsi_read(struct virtio_dev *, stru
 static int vioscsi_write(struct virtio_dev *, struct viodev_msg *);

 __dead void
-vioscsi_main(int fd, int fd_vmm)
+vioscsi_main(int fd, int vm_fd)
 {
 	struct virtio_dev	 dev;
 	struct vioscsi_dev	*vioscsi = NULL;
@@ -90,8 +90,8 @@ vioscsi_main(int fd, int fd_vmm)
 	vioscsi = &dev.vioscsi;

 	log_debug("%s: got vioscsi dev. cdrom fd = %d, syncfd = %d, "
-	    "asyncfd = %d, vmm fd = %d", __func__, vioscsi->cdrom_fd,
-	    dev.sync_fd, dev.async_fd, fd_vmm);
+	    "asyncfd = %d, vm fd = %d", __func__, vioscsi->cdrom_fd,
+	    dev.sync_fd, dev.async_fd, vm_fd);

 	/* Receive our vm information from the vm process. */
 	memset(&vm, 0, sizeof(vm));
@@ -107,16 +107,16 @@ vioscsi_main(int fd, int fd_vmm)
 	log_procinit("vm/%s/vioscsi", vm.vm_params.vmc_name);

 	/* Now that we have our vm information, we can remap memory. */
-	ret = remap_guest_mem(&vm, fd_vmm);
+	ret = remap_guest_mem(&vm, vm_fd);
 	if (ret) {
 		log_warnx("failed to remap guest memory");
 		goto fail;
 	}

 	/*
-	 * We no longer need /dev/vmm access.
+	 * We no longer need VM fd access.
 	 */
-	close_fd(fd_vmm);
+	close_fd(vm_fd);
 	if (pledge("stdio", NULL) == -1)
 		fatal("pledge2");

blob - 944e5c1d464fc3764d0d62969a19d5e744cee190
blob + fdeac6d559b54382b181a4be04f00f1089d8e720
--- usr.sbin/vmd/virtio.c
+++ usr.sbin/vmd/virtio.c
@@ -33,6 +33,7 @@

 #include <errno.h>
 #include <event.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -696,7 +697,7 @@ virtio_io_isr(int dir, uint16_t reg, uint32_t *data, u
 	if (dir == VEI_DIR_IN) {
 		*data = dev->isr;
 		dev->isr = 0;
-		vcpu_deassert_irq(dev->vmm_id, 0, dev->irq);
+		vcpu_deassert_irq(dev->vm_fd, 0, dev->irq);
 	}

 	return (0);
@@ -795,7 +796,7 @@ vmmci_ctl(struct virtio_dev *dev, unsigned int cmd)

 		/* Trigger interrupt */
 		dev->isr = VIRTIO_CONFIG_ISR_CONFIG_CHANGE;
-		vcpu_assert_irq(dev->vmm_id, 0, dev->irq);
+		vcpu_assert_irq(dev->vm_fd, 0, dev->irq);

 		/* Add ACK timeout */
 		tv.tv_sec = VMMCI_TIMEOUT_SHORT;
@@ -807,7 +808,7 @@ vmmci_ctl(struct virtio_dev *dev, unsigned int cmd)
 			v->cmd = cmd;

 			dev->isr = VIRTIO_CONFIG_ISR_CONFIG_CHANGE;
-			vcpu_assert_irq(dev->vmm_id, 0, dev->irq);
+			vcpu_assert_irq(dev->vm_fd, 0, dev->irq);
 		} else {
 			log_debug("%s: RTC sync skipped (guest does not "
 			    "support RTC sync)\n", __func__);
@@ -851,7 +852,7 @@ vmmci_ack(struct virtio_dev *dev, unsigned int cmd)
 		 */
 		if (v->cmd == 0) {
 			log_debug("%s: vm %u requested shutdown", __func__,
-			    dev->vmm_id);
+			    dev->vm_fd);
 			vm_pipe_send(&v->dev_pipe, VMMCI_SET_TIMEOUT_SHORT);
 			return;
 		}
@@ -866,13 +867,13 @@ vmmci_ack(struct virtio_dev *dev, unsigned int cmd)
 		 */
 		if (cmd == v->cmd) {
 			log_debug("%s: vm %u acknowledged shutdown request",
-			    __func__, dev->vmm_id);
+			    __func__, dev->vm_fd);
 			vm_pipe_send(&v->dev_pipe, VMMCI_SET_TIMEOUT_LONG);
 		}
 		break;
 	case VMMCI_SYNCRTC:
 		log_debug("%s: vm %u acknowledged RTC sync request",
-		    __func__, dev->vmm_id);
+		    __func__, dev->vm_fd);
 		v->cmd = VMMCI_NONE;
 		break;
 	default:
@@ -891,7 +892,7 @@ vmmci_timeout(int fd, short type, void *arg)
 		fatalx("%s: device is not a vmmci device", __func__);
 	v = &dev->vmmci;

-	log_debug("vm %u shutdown", dev->vmm_id);
+	log_debug("vm %u shutdown", dev->vm_fd);
 	vm_shutdown(v->cmd == VMMCI_REBOOT ? VMMCI_REBOOT : VMMCI_SHUTDOWN);
 }

@@ -980,7 +981,7 @@ vmmci_io(int dir, uint16_t reg, uint32_t *data, uint8_
 		case VIRTIO_CONFIG_ISR_STATUS:
 			*data = dev->isr;
 			dev->isr = 0;
-			vcpu_deassert_irq(dev->vmm_id, 0, dev->irq);
+			vcpu_deassert_irq(dev->vm_fd, 0, dev->irq);
 			break;
 		}
 	}
@@ -1111,7 +1112,7 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,

 			/* Device specific initializiation. */
 			dev->dev_type = VMD_DEVTYPE_NET;
-			dev->vmm_id = vm->vm_vmmid;
+			dev->vm_fd = vm->vm_fd;
 			dev->vionet.data_fd = child_taps[i];

 			/* MAC address has been assigned by the parent */
@@ -1180,7 +1181,7 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,

 			/* Device specific initialization. */
 			dev->dev_type = VMD_DEVTYPE_DISK;
-			dev->vmm_id = vm->vm_vmmid;
+			dev->vm_fd = vm->vm_fd;
 			dev->vioblk.seg_max = VIOBLK_SEG_MAX_DEFAULT;

 			/*
@@ -1228,7 +1229,7 @@ virtio_init(struct vmd_vm *vm, int child_cdrom,

 		/* Device specific initialization. */
 		dev->dev_type = VMD_DEVTYPE_SCSI;
-		dev->vmm_id = vm->vm_vmmid;
+		dev->vm_fd = vm->vm_fd;
 		dev->vioscsi.cdrom_fd = child_cdrom;
 		dev->vioscsi.locked = 0;
 		dev->vioscsi.lba = 0;
@@ -1421,7 +1422,7 @@ virtio_dev_init(struct vmd_vm *vm, struct virtio_dev *
 	dev->irq = pci_get_dev_irq(pci_id);
 	dev->isr = 0;
 	dev->vm_id = vm->vm_vmid;
-	dev->vmm_id = vm->vm_vmmid;
+	dev->vm_fd = vm->vm_fd;

 	dev->device_feature = features;

@@ -1684,14 +1685,24 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev
 			if (virtio_dev_closefds(dev_entry) == -1)
 				fatalx("unable to close other virtio devs");
 		}
+		/*
+		 * Device helpers only need the VM file descriptor passed via
+		 * argv -i for remap_guest_mem(); close inherited control fds.
+		 */
+		if (env->vmd_vmm_fd != -1 && env->vmd_vmm_fd != vm->vm_fd)
+			close_fd(env->vmd_vmm_fd);
+		if (env->vmd_psp_fd != -1 && env->vmd_psp_fd != vm->vm_fd)
+			close_fd(env->vmd_psp_fd);

 		memset(num, 0, sizeof(num));
 		snprintf(num, sizeof(num), "%d", sync_fds[1]);
 		memset(vmm_fd, 0, sizeof(vmm_fd));
-		snprintf(vmm_fd, sizeof(vmm_fd), "%d", env->vmd_vmm_fd);
+		snprintf(vmm_fd, sizeof(vmm_fd), "%d", vm->vm_fd);
 		memset(vm_name, 0, sizeof(vm_name));
 		snprintf(vm_name, sizeof(vm_name), "%s",
 		    vm->vm_params.vmc_name);
+		if (vm->vm_fd > 0)
+			fcntl(vm->vm_fd, F_SETFD, 0); /* keep vm fd across exec */

 		t[0] = dev->dev_type;
 		t[1] = '\0';
@@ -1820,14 +1831,14 @@ virtio_dispatch_dev(int fd, short event, void *arg)
 static int
 handle_dev_msg(struct viodev_msg *msg, struct virtio_dev *gdev)
 {
-	uint32_t vmm_id = gdev->vmm_id;
+	int vm_fd = gdev->vm_fd;

 	switch (msg->type) {
 	case VIODEV_MSG_KICK:
 		if (msg->state == INTR_STATE_ASSERT)
-			vcpu_assert_irq(vmm_id, msg->vcpu, msg->irq);
+			vcpu_assert_irq(vm_fd, msg->vcpu, msg->irq);
 		else if (msg->state == INTR_STATE_DEASSERT)
-			vcpu_deassert_irq(vmm_id, msg->vcpu, msg->irq);
+			vcpu_deassert_irq(vm_fd, msg->vcpu, msg->irq);
 		break;
 	case VIODEV_MSG_READY:
 		log_debug("%s: device reports ready", __func__);
@@ -1931,9 +1942,9 @@ virtio_pci_io(int dir, uint16_t reg, uint32_t *data, u
 			 * device performs a register read.
 			 */
 			if (msg.state == INTR_STATE_ASSERT)
-				vcpu_assert_irq(dev->vmm_id, msg.vcpu, msg.irq);
+				vcpu_assert_irq(dev->vm_fd, msg.vcpu, msg.irq);
 			else if (msg.state == INTR_STATE_DEASSERT)
-				vcpu_deassert_irq(dev->vmm_id, msg.vcpu, msg.irq);
+				vcpu_deassert_irq(dev->vm_fd, msg.vcpu, msg.irq);
 		} else {
 			log_warnx("%s: expected IO_READ, got %d", __func__,
 			    msg.type);
blob - 0af586eb6c5e599d8641020555f2f57411154b03
blob + ba591e18bd8dd5952bbd2090bdad573d387bff27
--- usr.sbin/vmd/virtio.h
+++ usr.sbin/vmd/virtio.h
@@ -341,10 +341,10 @@ struct virtio_dev {
 		/* Multi-process enabled. */
 		struct vioblk_dev vioblk;
 		struct vionet_dev vionet;
+		struct vioscsi_dev vioscsi;

 		/* In-process only. */
 		struct vmmci_dev vmmci;
-		struct vioscsi_dev vioscsi;
 	};

 	struct virtio_io_cfg		cfg;		/* Virtio 0.9 */
@@ -369,8 +369,8 @@ struct virtio_dev {
 	int sync_fd;				/* fd for synchronous channel */
 	int async_fd;				/* fd for async channel */

+	int		vm_fd;			/* vmm(4) vm file descriptor [r] */
 	uint32_t	vm_id;			/* vmd(8) vm identifier [r] */
-	uint32_t	vmm_id;			/* vmm(4) vm identifier [r] */
 	pid_t		dev_pid;		/* pid of emulator process */
 	char		dev_type;		/* device type (as char) */
 	SLIST_ENTRY(virtio_dev) dev_next;
blob - e67df7fd489fbe8b837ce9f8b6a58cb027f5c791
blob + afd8887458f8416c280a7b9165658cd5bc6a3fe9
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -194,10 +194,8 @@ start_vm(struct vmd_vm *vm, int fd)
 			errno = ret;
 			log_warn("could not create vm");
 		}
-
-		/* Let the vmm process know we failed by sending a 0 vm id. */
-		vm->vm_vmmid = 0;
-		atomicio(vwrite, fd, &vm->vm_vmmid, sizeof(vm->vm_vmmid));
+		/* Let the vmm process know we failed by sending the error code. */
+		atomicio(vwrite, fd, &ret, sizeof(ret));
 		return (ret);
 	}

@@ -217,14 +215,10 @@ start_vm(struct vmd_vm *vm, int fd)
 		log_warn("failed to set nonblocking mode on console");
 		return (1);
 	}
-
-	/*
-	 * We now let the vmm process know we were successful by sending it our
-	 * vmm(4) assigned vm id.
-	 */
-	if (atomicio(vwrite, fd, &vm->vm_vmmid, sizeof(vm->vm_vmmid)) !=
-	    sizeof(vm->vm_vmmid)) {
-		log_warn("failed to send created vm id to vmm process");
+	/* We now let the vmm process know we were successful. */
+	ret = 0;
+	if (atomicio(vwrite, fd, &ret, sizeof(ret)) != sizeof(ret)) {
+		log_warn("failed to send vm start status to vmm process");
 		return (1);
 	}

@@ -486,7 +480,7 @@ unpause_vm(struct vmd_vm *vm)
  * the register state provided
  *
  * Parameters
- *  vmid: VM ID to reset
+ *  fd: vm file descriptor to reset
  *  vcpu_id: VCPU ID to reset
  *  vrs: the register state to initialize
  *
@@ -496,18 +490,17 @@ unpause_vm(struct vmd_vm *vm)
  *      valid)
  */
 int
-vcpu_reset(uint32_t vmid, uint32_t vcpu_id, struct vcpu_reg_state *vrs)
+vcpu_reset(int fd, uint32_t vcpu_id, struct vcpu_reg_state *vrs)
 {
 	struct vm_resetcpu_params vrp;

 	memset(&vrp, 0, sizeof(vrp));
-	vrp.vrp_vm_id = vmid;
 	vrp.vrp_vcpu_id = vcpu_id;
 	memcpy(&vrp.vrp_init_state, vrs, sizeof(struct vcpu_reg_state));

-	log_debug("%s: resetting vcpu %d for vm %d", __func__, vcpu_id, vmid);
+	log_debug("%s: resetting vcpu %d", __func__, vcpu_id);

-	if (ioctl(env->vmd_vmm_fd, VMM_IOC_RESETCPU, &vrp) == -1)
+	if (ioctl(fd, VMM_IOC_RESETCPU, &vrp) == -1)
 		return (errno);

 	return (0);
@@ -557,10 +550,15 @@ vmm_create_vm(struct vmd_vm *vm)
 	vcp.vcp_sev = vmc->vmc_sev;
 	vcp.vcp_seves = vmc->vmc_seves;

-	if (ioctl(env->vmd_vmm_fd, VMM_IOC_CREATE, &vcp) == -1)
+	if (ioctl(env->vmd_vmm_fd, VMM_IOC_CREATE, &vcp) == -1) {
+		close_fd(env->vmd_vmm_fd);
+		env->vmd_vmm_fd = -1;
 		return (errno);
+	}
+	close_fd(env->vmd_vmm_fd);
+	env->vmd_vmm_fd = -1;

-	vm->vm_vmmid = vcp.vcp_id;
+	vm->vm_fd = vcp.vcp_fd;
 	for (i = 0; i < vcp.vcp_ncpus; i++)
 		vm->vm_sev_asid[i] = vcp.vcp_asid[i];
 	for (i = 0; i < vmc->vmc_nmemranges; i++)
@@ -641,10 +639,9 @@ run_vm(struct vmd_vm *vm, struct vcpu_reg_state *vrs)
 			/* caller will exit, so skip freeing */
 			return (ENOMEM);
 		}
-		vrp[i]->vrp_vm_id = vm->vm_vmmid;
 		vrp[i]->vrp_vcpu_id = i;

-		if (vcpu_reset(vm->vm_vmmid, i, vrs)) {
+		if (vcpu_reset(vm->vm_fd, i, vrs)) {
 			log_warnx("cannot reset vcpu %zu", i);
 			return (EIO);
 		}
@@ -894,7 +891,7 @@ vcpu_run_loop(void *arg)
 		/* Still more interrupts pending? */
 		vrp->vrp_intr_pending = intr_pending(current_vm);

-		if (ioctl(env->vmd_vmm_fd, VMM_IOC_RUN, vrp) == -1) {
+		if (ioctl(current_vm->vm_fd, VMM_IOC_RUN, vrp) == -1) {
 			/* If run ioctl failed, exit */
 			ret = errno;
 			log_warn("%s: vm %d / vcpu %d run ioctl failed",
@@ -931,17 +928,16 @@ vcpu_run_loop(void *arg)
 }

 int
-vcpu_intr(uint32_t vmm_id, uint32_t vcpu_id, uint8_t intr)
+vcpu_intr(int fd, uint32_t vcpu_id, uint8_t intr)
 {
 	struct vm_intr_params vip;

 	memset(&vip, 0, sizeof(vip));

-	vip.vip_vm_id = vmm_id;
 	vip.vip_vcpu_id = vcpu_id; /* XXX always 0? */
 	vip.vip_intr = intr;

-	if (ioctl(env->vmd_vmm_fd, VMM_IOC_INTR, &vip) == -1)
+	if (ioctl(fd, VMM_IOC_INTR, &vip) == -1)
 		return (errno);

 	return (0);
@@ -1096,7 +1092,7 @@ vm_pipe_recv(struct vm_dev_pipe *p)
  * Returns 0 on success or an errno in event of failure.
  */
 int
-remap_guest_mem(struct vmd_vm *vm, int vmm_fd)
+remap_guest_mem(struct vmd_vm *vm, int vm_fd)
 {
 	size_t i;
 	struct vm_sharemem_params vsp;
@@ -1106,17 +1102,12 @@ remap_guest_mem(struct vmd_vm *vm, int vmm_fd)

 	/* Initialize using our original creation parameters. */
 	memset(&vsp, 0, sizeof(vsp));
-	vsp.vsp_nmemranges = vm->vm_params.vmc_nmemranges;
-	vsp.vsp_vm_id = vm->vm_vmmid;
-	memcpy(&vsp.vsp_memranges, &vm->vm_params.vmc_memranges,
-	    sizeof(vsp.vsp_memranges));
-
 	/* Ask vmm(4) to enter a shared mapping to guest memory. */
-	if (ioctl(vmm_fd, VMM_IOC_SHAREMEM, &vsp) == -1)
+	if (ioctl(vm_fd, VMM_IOC_SHAREMEM, &vsp) == -1)
 		return (errno);

 	/* Update with the location of the new mappings. */
-	for (i = 0; i < vsp.vsp_nmemranges; i++)
+	for (i = 0; i < vm->vm_params.vmc_nmemranges; i++)
 		vm->vm_params.vmc_memranges[i].vmr_va = vsp.vsp_va[i];

 	return (0);
blob - 45be7b08b02cb06e87b3f34360743510332727ae
blob + 0c998bd8242ff364364bba1bcef2bd67cfce2c22
--- usr.sbin/vmd/vmd.c
+++ usr.sbin/vmd/vmd.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <limits.h>
 #include <event.h>
 #include <fcntl.h>
 #include <pwd.h>
@@ -238,7 +239,7 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, s
 			} else {
 				vid.vid_id = vm->vm_vmid;
 			}
-		} else if ((vm = vm_getbyid(vid.vid_id)) == NULL) {
+		} else if ((vm = vm_getbyvmid(vid.vid_id)) == NULL) {
 			res = ENOENT;
 			cmd = type == IMSG_VMDOP_PAUSE_VM
 			    ? IMSG_VMDOP_PAUSE_VM_RESPONSE
@@ -323,7 +324,6 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struc
 		if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL)
 			break;
 		vm->vm_pid = vmr.vmr_pid;
-		vm->vm_vmmid = vmr.vmr_id;

 		/*
 		 * If the peerid is not -1, forward the response back to the
@@ -599,13 +599,13 @@ main(int argc, char **argv)
 			break;
 		case 'V':
 			vm_launch = VMD_LAUNCH_VM;
-			vm_fd = strtonum(optarg, 0, 128, &errp);
+			vm_fd = strtonum(optarg, 0, INT_MAX, &errp);
 			if (errp)
 				fatalx("invalid vm fd");
 			break;
 		case 'X':
 			vm_launch = VMD_LAUNCH_DEV;
-			vm_fd = strtonum(optarg, 0, 128, &errp);
+			vm_fd = strtonum(optarg, 0, INT_MAX, &errp);
 			if (errp)
 				fatalx("invalid device fd");
 			break;
@@ -620,13 +620,13 @@ main(int argc, char **argv)
 			}
 			break;
 		case 'i':
-			vmm_fd = strtonum(optarg, 0, 128, &errp);
+			vmm_fd = strtonum(optarg, 0, INT_MAX, &errp);
 			if (errp)
 				fatalx("invalid vmm fd");
 			break;
 		case 'j':
 			/* -1 means no PSP available */
-			psp_fd = strtonum(optarg, -1, 128, &errp);
+			psp_fd = strtonum(optarg, -1, INT_MAX, &errp);
 			if (errp)
 				fatalx("invalid psp fd");
 			break;
@@ -962,43 +962,7 @@ vm_getbyvmid(uint32_t vmid)
 	return (NULL);
 }

-/* Find a vm in the list by it's vmm(4) id. */
 struct vmd_vm *
-vm_getbyid(uint32_t id)
-{
-	struct vmd_vm	*vm;
-
-	if (id == 0)
-		return (NULL);
-	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
-		if (vm->vm_vmmid == id)	// XXX check this
-			return (vm);
-	}
-
-	return (NULL);
-}
-
-/* Translate a kernel/vmm(4) vm id to a vmd(8) id. */
-uint32_t
-vm_id2vmid(uint32_t id, struct vmd_vm *vm)
-{
-	if (vm == NULL && (vm = vm_getbyid(id)) == NULL)
-		return (0);
-	DPRINTF("%s: vmm id %u is vmid %u", __func__,
-	    id, vm->vm_vmid);
-	return (vm->vm_vmid);
-}
-
-uint32_t
-vm_vmid2id(uint32_t vmid, struct vmd_vm *vm)
-{
-	if (vm == NULL && (vm = vm_getbyvmid(vmid)) == NULL)
-		return (0);
-	DPRINTF("%s: vmid %u is vmm id %u", __func__, vmid, vm->vm_vmmid);
-	return (vm->vm_vmmid);
-}
-
-struct vmd_vm *
 vm_getbyname(const char *name)
 {
 	struct vmd_vm	*vm;
@@ -1221,6 +1185,7 @@ vm_register(struct privsep *ps, struct vmop_create_par
 	vmc = &vm->vm_params;
 	vm->vm_pid = -1;
 	vm->vm_tty = -1;
+	vm->vm_fd = -1;
 	vm->vm_kernel = -1;
 	vm->vm_state &= ~VM_STATE_PAUSED;

blob - bfd2402fb03a98a0d0e08b20b18030519b410b89
blob + 260e4fbf72cd7eb78f44e845776092c715b2fc6f
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -308,7 +308,7 @@ struct vmd_vm {
 	pid_t			 vm_pid;
 	uid_t			 vm_uid;
 	uint32_t		 vm_vmid;	/* vmd(8) identifier */
-	uint32_t		 vm_vmmid;	/* vmm(4) identifier */
+	int			 vm_fd;		/* vmm(4) vm file descriptor */
 	uint32_t		 vm_peerid;

 	/* AMD SEV features */
@@ -471,10 +471,7 @@ ssize_t	 decode_udp_ip_header(unsigned char *, size_t,

 /* vmd.c */
 int	 vmd_reload(unsigned int, const char *);
-struct vmd_vm *vm_getbyid(uint32_t);
 struct vmd_vm *vm_getbyvmid(uint32_t);
-uint32_t vm_id2vmid(uint32_t, struct vmd_vm *);
-uint32_t vm_vmid2id(uint32_t, struct vmd_vm *);
 struct vmd_vm *vm_getbyname(const char *);
 struct vmd_vm *vm_getbypid(pid_t);
 void	 vm_stop(struct vmd_vm *, int, const char *);
@@ -525,7 +522,7 @@ void	 create_memory_map(struct vmd_vm *);
 int	 load_firmware(struct vmd_vm *, struct vcpu_reg_state *);
 int	 init_emulated_hw(struct vmd_vm *, int, int[][VM_MAX_BASE_PER_DISK],
     int *);
-int	 vcpu_reset(uint32_t, uint32_t, struct vcpu_reg_state *);
+int	 vcpu_reset(int, uint32_t, struct vcpu_reg_state *);
 void	 pause_vm_md(struct vmd_vm *);
 void	 unpause_vm_md(struct vmd_vm *);
 void	*hvaddr_mem(paddr_t, size_t);
@@ -536,8 +533,8 @@ int	 read_mem(paddr_t, void *, size_t);
 int	 intr_ack(struct vmd_vm *);
 int	 intr_pending(struct vmd_vm *);
 void	 intr_toggle_el(struct vmd_vm *, int, int);
-void	 vcpu_assert_irq(uint32_t, uint32_t, int);
-void	 vcpu_deassert_irq(uint32_t, uint32_t, int);
+void	 vcpu_assert_irq(int, uint32_t, int);
+void	 vcpu_deassert_irq(int, uint32_t, int);
 int	 vcpu_exit(struct vm_run_params *);
 uint8_t	 vcpu_exit_pci(struct vm_run_params *);

@@ -551,7 +548,7 @@ void	 get_input_data(struct vm_exit *, uint32_t *);
 void	 vcpu_halt(uint32_t);
 void	 vcpu_unhalt(uint32_t);
 void	 vcpu_signal_run(uint32_t);
-int 	 vcpu_intr(uint32_t, uint32_t, uint8_t);
+int 	 vcpu_intr(int, uint32_t, uint8_t);
 void	 vm_main(int, int);
 void	 mutex_lock(pthread_mutex_t *);
 void	 mutex_unlock(pthread_mutex_t *);
@@ -600,7 +597,7 @@ int	 psp_df_flush(void);
 int	 psp_get_gstate(uint32_t, uint32_t *, uint32_t *, uint8_t *);
 int	 psp_launch_start(uint32_t *, int);
 int	 psp_launch_update(uint32_t, vaddr_t, size_t);
-int	 psp_encrypt_state(uint32_t, uint32_t, uint32_t, uint32_t);
+int	 psp_encrypt_state(uint32_t, uint32_t, int, uint32_t);
 int	 psp_launch_measure(uint32_t);
 int	 psp_launch_finish(uint32_t);
 int	 psp_activate(uint32_t, uint32_t);
blob - 1aa639cdf3028e90b8a155d51cc73ecbdc7c0cdb
blob + 2b3953df66b4d2a0cf8fa6a1329f64da5dc8aa1d
--- usr.sbin/vmd/vmm.c
+++ usr.sbin/vmd/vmm.c
@@ -21,6 +21,7 @@
 #include <sys/queue.h>
 #include <sys/wait.h>
 #include <sys/socket.h>
+#include <signal.h>

 #include <dev/vmm/vmm.h>

@@ -45,7 +46,7 @@ int	vmm_start_vm(struct imsg *, uint32_t *, pid_t *);
 int	vmm_dispatch_parent(int, struct privsep_proc *, struct imsg *);
 void	vmm_run(struct privsep *, struct privsep_proc *, void *);
 void	vmm_dispatch_vm(int, short, void *);
-int	terminate_vm(struct vm_terminate_params *);
+int	terminate_vm(pid_t);
 int	get_info_vm(struct privsep *, struct imsg *, int);
 int	opentap(char *);

@@ -108,7 +109,6 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, st
 	struct privsep		*ps = p->p_ps;
 	int			 res = 0, cmd = IMSG_NONE, verbose;
 	struct vmd_vm		*vm = NULL;
-	struct vm_terminate_params vtp;
 	struct vmop_id		 vid;
 	struct vmop_result	 vmr;
 	struct vmop_addr_result  var;
@@ -153,9 +153,6 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, st
 		break;
 	case IMSG_VMDOP_START_VM_END:
 		res = vmm_start_vm(imsg, &id, &vm_pid);
-		/* Check if the ID can be mapped correctly */
-		if (res == 0 && (id = vm_id2vmid(id, NULL)) == 0)
-			res = ENOENT;
 		cmd = IMSG_VMDOP_START_VM_RESPONSE;
 		break;
 	case IMSG_VMDOP_TERMINATE_VM_REQUEST:
@@ -171,10 +168,8 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, st
 			res = ENOENT;
 		} else if ((vm = vm_getbyvmid(id)) != NULL) {
 			if (flags & VMOP_FORCE) {
-				vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
 				vm->vm_state |= VM_STATE_SHUTDOWN;
-				(void)terminate_vm(&vtp);
-				res = 0;
+				res = terminate_vm(vm->vm_pid);
 			} else if (!(vm->vm_state & VM_STATE_SHUTDOWN)) {
 				log_debug("%s: sending shutdown request"
 				    " to vm %d", __func__, id);
@@ -199,7 +194,7 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, st
 				 * Check to see if the VM process is still
 				 * active.  If not, return VMD_VM_STOP_INVALID.
 				 */
-				if (vm_vmid2id(vm->vm_vmid, vm) == 0) {
+				if (kill(vm->vm_pid, 0) == -1 && errno == ESRCH) {
 					log_debug("%s: no vm running anymore",
 					    __func__);
 					res = VMD_VM_STOP_INVALID;
@@ -327,11 +322,10 @@ void
 vmm_sighdlr(int sig, short event, void *arg)
 {
 	struct privsep *ps = arg;
-	int status, ret = 0;
+	int status, ret;
 	pid_t pid;
 	struct vmop_result vmr;
 	struct vmd_vm *vm;
-	struct vm_terminate_params vtp;

 	log_debug("%s: handling signal %d", __func__, sig);
 	switch (sig) {
@@ -340,6 +334,7 @@ vmm_sighdlr(int sig, short event, void *arg)
 			pid = waitpid(-1, &status, WNOHANG);
 			if (pid <= 0)
 				continue;
+			ret = 0;

 			if (WIFEXITED(status) || WIFSIGNALED(status)) {
 				vm = vm_getbypid(pid);
@@ -354,24 +349,21 @@ vmm_sighdlr(int sig, short event, void *arg)

 				if (WIFEXITED(status))
 					ret = WEXITSTATUS(status);
+				else if (WIFSIGNALED(status))
+					ret = EIO;

 				/* Don't reboot on pending shutdown */
 				if (ret == EAGAIN &&
 				    (vm->vm_state & VM_STATE_SHUTDOWN))
 					ret = 0;

-				/* XXX check this */
-				vtp.vtp_vm_id = vm->vm_vmmid;
+				log_debug("%s: vm %s exited (id %d)",
+				    __func__, vm->vm_params.vmc_name,
+				    vm->vm_vmid);

-				if (terminate_vm(&vtp) == 0)
-					log_debug("%s: terminated vm %s"
-					    " (id %d)", __func__,
-					    vm->vm_params.vmc_name,
-					    vm->vm_vmid);
-
 				memset(&vmr, 0, sizeof(vmr));
 				vmr.vmr_result = ret;
-				vmr.vmr_id = vm_id2vmid(vm->vm_vmmid, vm);
+				vmr.vmr_id = vm->vm_vmid;
 				if (proc_compose_imsg(ps, PROC_PARENT,
 				    IMSG_VMDOP_TERMINATE_VM_EVENT,
 				    vm->vm_peerid, -1, &vmr, sizeof(vmr)) == -1)
@@ -397,14 +389,11 @@ vmm_sighdlr(int sig, short event, void *arg)
 void
 vmm_shutdown(void)
 {
-	struct vm_terminate_params vtp;
 	struct vmd_vm *vm, *vm_next;

 	TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, vm_next) {
-		vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
-
 		/* XXX suspend or request graceful shutdown */
-		(void)terminate_vm(&vtp);
+		(void)terminate_vm(vm->vm_pid);
 		vm_remove(vm, __func__);
 	}
 }
@@ -514,23 +503,18 @@ vmm_dispatch_vm(int fd, short event, void *arg)
 	imsg_event_add(iev);
 }

-/*
- * terminate_vm
- *
- * Requests vmm(4) to terminate the VM whose ID is provided in the
- * supplied vm_terminate_params structure (vtp->vtp_vm_id)
- *
- * Parameters
- *  vtp: vm_terminate_params struct containing the ID of the VM to terminate
- *
- * Return values:
- *  0: success
- *  !0: ioctl to vmm(4) failed (eg, ENOENT if the supplied VM is not valid)
- */
 int
-terminate_vm(struct vm_terminate_params *vtp)
+terminate_vm(pid_t pid)
 {
-	if (ioctl(env->vmd_vmm_fd, VMM_IOC_TERM, vtp) == -1)
+	struct vm_terminate_params vtp;
+
+	if (pid <= 0)
+		return (EINVAL);
+
+	memset(&vtp, 0, sizeof(vtp));
+	vtp.vtp_creator_pid = pid;
+
+	if (ioctl(env->vmd_vmm_fd, VMM_IOC_TERM, &vtp) == -1)
 		return (errno);

 	return (0);
@@ -588,7 +572,7 @@ opentap(char *ifname)
  *
  * Parameters:
  *  imsg: The VM data structure that is including the VM create parameters.
- *  id: Returns the VM id as reported by the kernel and obtained from the VM.
+ *  id: Returns the vmd(8) VM identifier.
  *  pid: Returns the VM pid to the parent.
  *
  * Return values:
@@ -686,22 +670,19 @@ vmm_start_vm(struct imsg *imsg, uint32_t *id, pid_t *p
 			goto err;
 		}

-		/* Read back the kernel-generated vm id from the child */
-		sz = atomicio(read, fds[0], &vm->vm_vmmid,
-		    sizeof(vm->vm_vmmid));
-		if (sz != sizeof(vm->vm_vmmid)) {
-			log_debug("%s: failed to receive vm id from vm %s",
+		/* Read back the VM start status from the child. */
+		sz = atomicio(read, fds[0], &ret, sizeof(ret));
+		if (sz != sizeof(ret)) {
+			log_debug("%s: failed to receive vm start status from vm %s",
 			    __func__, vm->vm_params.vmc_name);
-			/* vmd could not allocate memory for the vm. */
-			ret = ENOMEM;
+			ret = EIO;
 			goto err;
 		}

-		/* Check for an invalid id. This indicates child failure. */
-		if (vm->vm_vmmid == 0)
+		if (ret != 0)
 			goto err;

-		*id = vm->vm_vmmid;
+		*id = vm->vm_vmid;
 		*pid = vm->vm_pid;

 		/* Wire up our pipe into the event handling. */
@@ -724,6 +705,8 @@ vmm_start_vm(struct imsg *imsg, uint32_t *id, pid_t *p
 				close(dev_null);
 		}

+		if (env->vmd_vmm_fd > 0)
+			fcntl(env->vmd_vmm_fd, F_SETFD, 0); /* /dev/vmm fd */
 		if (env->vmd_psp_fd > 0)
 			fcntl(env->vmd_psp_fd, F_SETFD, 0); /* psp device fd */

@@ -795,8 +778,8 @@ get_info_vm(struct privsep *ps, struct imsg *imsg, int
 	size_t ct, i;
 	struct vm_info_params vip;
 	struct vm_info_result *info;
-	struct vm_terminate_params vtp;
 	struct vmop_info_result vir;
+	struct vmd_vm *vm;
 	uint32_t peer_id;

 	/*
@@ -839,11 +822,10 @@ get_info_vm(struct privsep *ps, struct imsg *imsg, int
 	ct = vip.vip_size / sizeof(struct vm_info_result);
 	for (i = 0; i < ct; i++) {
 		if (terminate) {
-			vtp.vtp_vm_id = info[i].vir_id;
-			if ((ret = terminate_vm(&vtp)) != 0)
+			if ((ret = terminate_vm(info[i].vir_creator_pid)) != 0)
 				break;
-			log_debug("%s: terminated vm %s (id %d)", __func__,
-			    info[i].vir_name, info[i].vir_id);
+			log_debug("%s: terminated vm %s (pid %d)", __func__,
+			    info[i].vir_name, info[i].vir_creator_pid);
 			continue;
 		}

@@ -854,7 +836,9 @@ get_info_vm(struct privsep *ps, struct imsg *imsg, int
 		memcpy(vir.vir_vcpu_state, info[i].vir_vcpu_state,
 		    sizeof(vir.vir_vcpu_state));
 		vir.vir_creator_pid = info[i].vir_creator_pid;
-		vir.vir_id = vm_id2vmid(info[i].vir_id, NULL);
+		if ((vm = vm_getbypid(info[i].vir_creator_pid)) == NULL)
+			continue;
+		vir.vir_id = vm->vm_vmid;
 		memcpy(vir.vir_name, info[i].vir_name, sizeof(vir.vir_name));

 		peer_id = imsg_get_id(imsg);
blob - 1b5ade90f9b3152a37bcc54a2fadd6e8a71fbac7
blob + 235cb1f2c53747da6955850a2f94e7e8aad3aba3
--- usr.sbin/vmd/x86_vm.c
+++ usr.sbin/vmd/x86_vm.c
@@ -368,7 +368,7 @@ init_emulated_hw(struct vmd_vm *vm, int child_cdrom,
 	memset(&ioports_map, 0, sizeof(io_fn_t) * MAX_PORTS);

 	/* Init i8253 PIT */
-	i8253_init(vm->vm_vmmid);
+	i8253_init(vm->vm_fd);
 	ioports_map[TIMER_CTRL] = vcpu_exit_i8253;
 	ioports_map[TIMER_BASE + TIMER_CNTR0] = vcpu_exit_i8253;
 	ioports_map[TIMER_BASE + TIMER_CNTR1] = vcpu_exit_i8253;
@@ -376,7 +376,7 @@ init_emulated_hw(struct vmd_vm *vm, int child_cdrom,
 	ioports_map[PCKBC_AUX] = vcpu_exit_i8253_misc;

 	/* Init mc146818 RTC */
-	mc146818_init(vm->vm_vmmid, memlo, memhi);
+	mc146818_init(vm->vm_fd, memlo, memhi);
 	ioports_map[IO_RTC] = vcpu_exit_mc146818;
 	ioports_map[IO_RTC + 1] = vcpu_exit_mc146818;

@@ -390,7 +390,7 @@ init_emulated_hw(struct vmd_vm *vm, int child_cdrom,
 	ioports_map[ELCR1] = vcpu_exit_elcr;

 	/* Init ns8250 UART */
-	ns8250_init(con_fd, vm->vm_vmmid);
+	ns8250_init(con_fd, vm->vm_fd);
 	for (i = COM1_DATA; i <= COM1_SCR; i++)
 		ioports_map[i] = vcpu_exit_com;

@@ -482,7 +482,7 @@ vcpu_exit_inout(struct vm_run_params *vrp)
 	vei->vrs.vrs_gprs[VCPU_REGS_RIP] += vei->vei.vei_insn_len;

 	if (intr != 0xFF)
-		vcpu_assert_irq(vrp->vrp_vm_id, vrp->vrp_vcpu_id, intr);
+		vcpu_assert_irq(current_vm->vm_fd, vrp->vrp_vcpu_id, intr);
 }

 /*
@@ -883,17 +883,17 @@ hvaddr_mem(paddr_t gpa, size_t len)
  * Injects the specified IRQ on the supplied vcpu/vm
  *
  * Parameters:
- *  vm_id: VMM vm ID to inject to
+ *  fd: vmm(4) vm file descriptor to inject to
  *  vcpu_id: VCPU ID to inject to
  *  irq: IRQ to inject
  */
 void
-vcpu_assert_irq(uint32_t vmm_id, uint32_t vcpu_id, int irq)
+vcpu_assert_irq(int fd, uint32_t vcpu_id, int irq)
 {
 	i8259_assert_irq(irq);

 	if (i8259_is_pending()) {
-		if (vcpu_intr(vmm_id, vcpu_id, 1))
+		if (vcpu_intr(fd, vcpu_id, 1))
 			fatalx("%s: can't assert INTR", __func__);

 		vcpu_unhalt(vcpu_id);
@@ -907,19 +907,19 @@ vcpu_assert_irq(uint32_t vmm_id, uint32_t vcpu_id, int
  * Clears the specified IRQ on the supplied vcpu/vm
  *
  * Parameters:
- *  vm_id: VMM vm ID to clear in
+ *  fd: vmm(4) vm file descriptor to clear in
  *  vcpu_id: VCPU ID to clear in
  *  irq: IRQ to clear
  */
 void
-vcpu_deassert_irq(uint32_t vmm_id, uint32_t vcpu_id, int irq)
+vcpu_deassert_irq(int fd, uint32_t vcpu_id, int irq)
 {
 	i8259_deassert_irq(irq);

 	if (!i8259_is_pending()) {
-		if (vcpu_intr(vmm_id, vcpu_id, 0))
-			fatalx("%s: can't deassert INTR for vmm_id %d, "
-			    "vcpu_id %d", __func__, vmm_id, vcpu_id);
+		if (vcpu_intr(fd, vcpu_id, 0))
+			fatalx("%s: can't deassert INTR for vm fd %d, "
+			    "vcpu_id %d", __func__, fd, vcpu_id);
 	}
 }