Index | Thread | Search

From:
Hans-Jörg Höxer <hshoexer@genua.de>
Subject:
Re: [EXT] Re: tests wanted: vmm(4)/vmd(8) fd-ification
To:
<tech@openbsd.org>
Date:
Mon, 10 Aug 2026 10:18:20 +0200

Download raw body.

Thread
Hi,

On Thu, Aug 06, 2026 at 05:09:35PM -0400, Dave Voutila wrote:
> Dave Voutila <dv@sisu.io> writes:
> 
> Another update, fixing building GENERIC. Missed some ifdefs for
> MULTIPROCESSOR.
> 

I'm running that latest diff with both SEV and SEV-ES VMs and see no
regressions so far.

> > Updated diff that applies to the tree again. Recent commit to vmd(8)
> > broke the original diff.
> >
> > There's a different vmd commit I'm making later today but by my testing
> > that shouldn't conflict with this diff.
> >
> > Dave Voutila <dv@sisu.io> writes:
> >
> >> 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
> >
> > Also, you need sys/file.h --> sys/sys/file.h if building fstat(1).
> >
> >> 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 - 38556f9d88df4854f048afb0c11bd3147ec2e92a
> commit + 91e058aa117d01c4f432feec6553fdd866bb3818
> 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 - cc621a8eee3faf2521b1c9ba014b8dee77cacfc9
> blob + 05ae299446902adcf3489b3a1dea4e7231fc18d9
> --- share/man/man4/man4.amd64/vmm.4
> +++ share/man/man4/man4.amd64/vmm.4
> @@ -14,7 +14,7 @@
>  .\"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>  .\"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  .\"
> -.Dd $Mdocdate: November 5 2024 $
> +.Dd $Mdocdate: March 2 2026 $
>  .Dt VMM 4 amd64
>  .Os
>  .Sh NAME
> @@ -72,23 +72,53 @@ For more information, consult the CPU vendor's documen
>  .Pp
>  The following
>  .Xr ioctl 2
> -commands are provided for managing
> -.Nm
> -guests:
> +commands are provided through two interfaces:
>  .Bl -tag -width Ds -offset indent
> +.It Pa /dev/vmm
> +Control device for creating VMs and querying system-wide VM information.
> +.It VM file descriptor
> +Per-VM handle returned by
> +.Dv VMM_IOC_CREATE .
> +The lifetime of a VM is tied to this descriptor; closing it tears down the VM.
> +.El
> +.Pp
> +The following ioctl calls apply to the
> +.Pa /dev/vmm
> +control device:
> +.Bl -tag -width Ds -offset indent
>  .It Dv VMM_IOC_CREATE Fa "struct vm_create_params *"
> -Create a VM, initializing
> +Create a VM via
> +.Pa /dev/vmm ,
> +initializing
>  .Nm
>  if not yet started.
> +Returns a VM file descriptor in
> +.Fa vcp_fd .
>  (Does not start the VCPU.)
> -.It Dv VMM_IOC_RUN Fa "struct vm_run_params *"
> -Run a VCPU for a defined VM.
> -Return on VM-exit, when the VCPU stopped, or an error occurred.
>  .It Dv VMM_IOC_INFO Fa "struct vm_info_params *"
>  Get information about the VMs currently hosted by
>  .Nm .
>  .It Dv VMM_IOC_TERM Fa "struct vm_terminate_params *"
> -Terminate a given VM.
> +Request termination of the VM whose creator PID matches
> +.Fa vtp_creator_pid .
> +This ioctl is issued on
> +.Pa /dev/vmm .
> +It marks the VM for termination and requests running VCPUs to stop.
> +Final cleanup happens when the last VM file descriptor reference is closed.
> +.Pp
> +All other ioctls, including
> +.Dv VMM_IOC_INTR ,
> +are unsupported on
> +.Pa /dev/vmm
> +and return
> +.Dv ENOTTY .
> +.El
> +.Pp
> +The following ioctl calls apply to the VM file descriptor returned by
> +.Dv VMM_IOC_CREATE .
> +.Bl -tag -width Ds -offset indent
> +.It Dv VMM_IOC_RUN Fa "struct vm_run_params *"
> +Run a VCPU and return on VM-exit, when the VCPU stopped, or on error.
>  .It Dv VMM_IOC_RESETCPU Fa "struct vm_resetcpu_params *"
>  Reset a VCPU to power-on-init state using the provided register state.
>  .It Dv VMM_IOC_INTR Fa "struct vm_intr_params *"
> @@ -105,6 +135,8 @@ version) for a VM.
>  Write paravirtualized hardware parameters (such as
>  .Xr pvclock 4
>  guest physical address) for a VM.
> +.It Dv VMM_IOC_SHAREMEM Fa "struct vm_sharemem_params *"
> +Create shared mappings for the VM memory ranges into the calling process.
>  .El
>  .Sh SEE ALSO
>  .Xr cpu 4 ,
> 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 + 86fe6b5292f8b770d8d410314b1caafd474443f1
> --- 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,94 @@ 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;
> 
> +#ifdef MULTIPROCESSOR
> +	int relock = _kernel_lock_held();
> +	if (relock)
> +		KERNEL_UNLOCK();
> +#endif
> +
> +	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);
> -	}
> -
> -	/* 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);
> +	error = 0;
> +out:
> +#ifdef MULTIPROCESSOR
> +	if (relock)
> +		KERNEL_LOCK();
> +#endif
> +	return (error);
>  }
> 
>  /*
> @@ -774,27 +823,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 +851,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 +874,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 +892,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 +921,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 +935,228 @@ 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;
> +	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.
> +	 */
> +#ifdef MULTIPROCESSOR
> +	int relock = _kernel_lock_held();
> +	if (relock)
> +		KERNEL_UNLOCK();
> +#endif
> +
> +	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);
> +#ifdef MULTIPROCESSOR
> +		if (relock)
> +			KERNEL_LOCK();
> +#endif
> +		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);
> +	}
> +
> +#ifdef MULTIPROCESSOR
> +	if (relock)
> +		KERNEL_LOCK();
> +#endif
> +	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 - 6523170fc35095565d2b6627c2adea9667e52d48
> blob + adc14142bfd8daa0834a9d2343c0cdc37a5f8981
> --- 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 - 5ba13f4e9ce09879dc39ff5ca6ce149865810976
> blob + d1c7e3feb97767265c410410941f46a932850942
> --- 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 - 355ce4069ff94b056a5f649dca64e4f49acf66ad
> blob + b012d39fcfe5ff475c962d58d38b312eb27ed640
> --- 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 - 03a6e761dfc183f147434028b796ec1c03f3790d
> blob + e24a5b4478ce61ba85514c93c1e4570023bd7cef
> --- 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)", __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 - ff4551814eafc8d0284ae40e63d53824737d8431
> blob + 6d9dd95ed0c33bd783d6d5475aabe82d0c7392c8
> --- 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);
>  	}
> 
> @@ -485,7 +479,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
>   *
> @@ -495,18 +489,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);
> @@ -556,10 +549,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++)
> @@ -640,10 +638,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);
>  		}
> @@ -893,7 +890,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",
> @@ -930,17 +927,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);
> @@ -1095,7 +1091,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;
> @@ -1105,17 +1101,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 - 47b393cb5742bb3c2cf411aea27b32234c8ae04f
> blob + 2da0e8da179f32238ec2c7b8cb5c6c1ba0b4b894
> --- 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);
>  	}
>  }
> 

-- 
Dr. Hans-Jörg Höxer                   Hans-Joerg_Hoexer@genua.de
Senior Expert Kryptographie
eXtreme Kernel and Crypto Development

genua GmbH
Domagkstrasse 7, 85551 Kirchheim bei München
tel +49 89 991950-0, fax -999, www.genua.eu

Geschäftsführer: Matthias Ochs, Marc Tesch
Amtsgericht München HRB 98238
genua ist ein Unternehmen der Bundesdruckerei-Gruppe.