diff options
Diffstat (limited to 'sys/amd64/vmm')
| -rw-r--r-- | sys/amd64/vmm/vmm.c | 187 | ||||
| -rw-r--r-- | sys/amd64/vmm/vmm_dev_machdep.c | 255 | ||||
| -rw-r--r-- | sys/amd64/vmm/vmm_mem.h | 5 | ||||
| -rw-r--r-- | sys/amd64/vmm/vmm_mem_machdep.c | 61 | 
4 files changed, 350 insertions, 158 deletions
| diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index 2ac076551165..f2bea0d82b5c 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -562,9 +562,9 @@ vm_alloc_vcpu(struct vm *vm, int vcpuid)  }  void -vm_slock_vcpus(struct vm *vm) +vm_lock_vcpus(struct vm *vm)  { -	sx_slock(&vm->vcpus_init_lock); +	sx_xlock(&vm->vcpus_init_lock);  }  void @@ -724,12 +724,7 @@ vm_name(struct vm *vm)  int  vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa)  { -	vm_object_t obj; - -	if ((obj = vmm_mmio_alloc(vm_vmspace(vm), gpa, len, hpa)) == NULL) -		return (ENOMEM); -	else -		return (0); +	return (vmm_mmio_alloc(vm_vmspace(vm), gpa, len, hpa));  }  int @@ -870,7 +865,7 @@ vm_assign_pptdev(struct vm *vm, int bus, int slot, int func)  int  vm_get_register(struct vcpu *vcpu, int reg, uint64_t *retval)  { - +	/* Negative values represent VM control structure fields. */  	if (reg >= VM_REG_LAST)  		return (EINVAL); @@ -882,6 +877,7 @@ vm_set_register(struct vcpu *vcpu, int reg, uint64_t val)  {  	int error; +	/* Negative values represent VM control structure fields. */  	if (reg >= VM_REG_LAST)  		return (EINVAL); @@ -990,6 +986,54 @@ save_guest_fpustate(struct vcpu *vcpu)  static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); +/* + * Invoke the rendezvous function on the specified vcpu if applicable.  Return + * true if the rendezvous is finished, false otherwise. + */ +static bool +vm_rendezvous(struct vcpu *vcpu) +{ +	struct vm *vm = vcpu->vm; +	int vcpuid; + +	mtx_assert(&vcpu->vm->rendezvous_mtx, MA_OWNED); +	KASSERT(vcpu->vm->rendezvous_func != NULL, +	    ("vm_rendezvous: no rendezvous pending")); + +	/* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ +	CPU_AND(&vm->rendezvous_req_cpus, &vm->rendezvous_req_cpus, +	    &vm->active_cpus); + +	vcpuid = vcpu->vcpuid; +	if (CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && +	    !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { +		VMM_CTR0(vcpu, "Calling rendezvous func"); +		(*vm->rendezvous_func)(vcpu, vm->rendezvous_arg); +		CPU_SET(vcpuid, &vm->rendezvous_done_cpus); +	} +	if (CPU_CMP(&vm->rendezvous_req_cpus, +	    &vm->rendezvous_done_cpus) == 0) { +		VMM_CTR0(vcpu, "Rendezvous completed"); +		CPU_ZERO(&vm->rendezvous_req_cpus); +		vm->rendezvous_func = NULL; +		wakeup(&vm->rendezvous_func); +		return (true); +	} +	return (false); +} + +static void +vcpu_wait_idle(struct vcpu *vcpu) +{ +	KASSERT(vcpu->state != VCPU_IDLE, ("vcpu already idle")); + +	vcpu->reqidle = 1; +	vcpu_notify_event_locked(vcpu, false); +	VMM_CTR1(vcpu, "vcpu state change from %s to " +	    "idle requested", vcpu_state2str(vcpu->state)); +	msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); +} +  static int  vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate,      bool from_idle) @@ -1004,13 +1048,8 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate,  	 * ioctl() operating on a vcpu at any point.  	 */  	if (from_idle) { -		while (vcpu->state != VCPU_IDLE) { -			vcpu->reqidle = 1; -			vcpu_notify_event_locked(vcpu, false); -			VMM_CTR1(vcpu, "vcpu state change from %s to " -			    "idle requested", vcpu_state2str(vcpu->state)); -			msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); -		} +		while (vcpu->state != VCPU_IDLE) +			vcpu_wait_idle(vcpu);  	} else {  		KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from "  		    "vcpu idle state")); @@ -1062,6 +1101,95 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate,  	return (0);  } +/* + * Try to lock all of the vCPUs in the VM while taking care to avoid deadlocks + * with vm_smp_rendezvous(). + * + * The complexity here suggests that the rendezvous mechanism needs a rethink. + */ +int +vcpu_set_state_all(struct vm *vm, enum vcpu_state newstate) +{ +	cpuset_t locked; +	struct vcpu *vcpu; +	int error, i; +	uint16_t maxcpus; + +	KASSERT(newstate != VCPU_IDLE, +	    ("vcpu_set_state_all: invalid target state %d", newstate)); + +	error = 0; +	CPU_ZERO(&locked); +	maxcpus = vm->maxcpus; + +	mtx_lock(&vm->rendezvous_mtx); +restart: +	if (vm->rendezvous_func != NULL) { +		/* +		 * If we have a pending rendezvous, then the initiator may be +		 * blocked waiting for other vCPUs to execute the callback.  The +		 * current thread may be a vCPU thread so we must not block +		 * waiting for the initiator, otherwise we get a deadlock. +		 * Thus, execute the callback on behalf of any idle vCPUs. +		 */ +		for (i = 0; i < maxcpus; i++) { +			vcpu = vm_vcpu(vm, i); +			if (vcpu == NULL) +				continue; +			vcpu_lock(vcpu); +			if (vcpu->state == VCPU_IDLE) { +				(void)vcpu_set_state_locked(vcpu, VCPU_FROZEN, +				    true); +				CPU_SET(i, &locked); +			} +			if (CPU_ISSET(i, &locked)) { +				/* +				 * We can safely execute the callback on this +				 * vCPU's behalf. +				 */ +				vcpu_unlock(vcpu); +				(void)vm_rendezvous(vcpu); +				vcpu_lock(vcpu); +			} +			vcpu_unlock(vcpu); +		} +	} + +	/* +	 * Now wait for remaining vCPUs to become idle.  This may include the +	 * initiator of a rendezvous that is currently blocked on the rendezvous +	 * mutex. +	 */ +	CPU_FOREACH_ISCLR(i, &locked) { +		if (i >= maxcpus) +			break; +		vcpu = vm_vcpu(vm, i); +		if (vcpu == NULL) +			continue; +		vcpu_lock(vcpu); +		while (vcpu->state != VCPU_IDLE) { +			mtx_unlock(&vm->rendezvous_mtx); +			vcpu_wait_idle(vcpu); +			vcpu_unlock(vcpu); +			mtx_lock(&vm->rendezvous_mtx); +			if (vm->rendezvous_func != NULL) +				goto restart; +			vcpu_lock(vcpu); +		} +		error = vcpu_set_state_locked(vcpu, newstate, true); +		vcpu_unlock(vcpu); +		if (error != 0) { +			/* Roll back state changes. */ +			CPU_FOREACH_ISSET(i, &locked) +				(void)vcpu_set_state(vcpu, VCPU_IDLE, false); +			break; +		} +		CPU_SET(i, &locked); +	} +	mtx_unlock(&vm->rendezvous_mtx); +	return (error); +} +  static void  vcpu_require_state(struct vcpu *vcpu, enum vcpu_state newstate)  { @@ -1083,36 +1211,23 @@ vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate)  static int  vm_handle_rendezvous(struct vcpu *vcpu)  { -	struct vm *vm = vcpu->vm; +	struct vm *vm;  	struct thread *td; -	int error, vcpuid; -	error = 0; -	vcpuid = vcpu->vcpuid;  	td = curthread; +	vm = vcpu->vm; +  	mtx_lock(&vm->rendezvous_mtx);  	while (vm->rendezvous_func != NULL) { -		/* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ -		CPU_AND(&vm->rendezvous_req_cpus, &vm->rendezvous_req_cpus, &vm->active_cpus); - -		if (CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && -		    !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus)) { -			VMM_CTR0(vcpu, "Calling rendezvous func"); -			(*vm->rendezvous_func)(vcpu, vm->rendezvous_arg); -			CPU_SET(vcpuid, &vm->rendezvous_done_cpus); -		} -		if (CPU_CMP(&vm->rendezvous_req_cpus, -		    &vm->rendezvous_done_cpus) == 0) { -			VMM_CTR0(vcpu, "Rendezvous completed"); -			CPU_ZERO(&vm->rendezvous_req_cpus); -			vm->rendezvous_func = NULL; -			wakeup(&vm->rendezvous_func); +		if (vm_rendezvous(vcpu))  			break; -		} +  		VMM_CTR0(vcpu, "Wait for rendezvous completion");  		mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0,  		    "vmrndv", hz);  		if (td_ast_pending(td, TDA_SUSPEND)) { +			int error; +  			mtx_unlock(&vm->rendezvous_mtx);  			error = thread_check_susp(td, true);  			if (error != 0) diff --git a/sys/amd64/vmm/vmm_dev_machdep.c b/sys/amd64/vmm/vmm_dev_machdep.c index dfebc9dcadbf..b84be809ea24 100644 --- a/sys/amd64/vmm/vmm_dev_machdep.c +++ b/sys/amd64/vmm/vmm_dev_machdep.c @@ -124,12 +124,16 @@ const struct vmmdev_ioctl vmmdev_machdep_ioctls[] = {  	VMMDEV_IOCTL(VM_SET_KERNEMU_DEV, VMMDEV_IOCTL_LOCK_ONE_VCPU),  	VMMDEV_IOCTL(VM_BIND_PPTDEV, -	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS), +	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS | +	    VMMDEV_IOCTL_PRIV_CHECK_DRIVER),  	VMMDEV_IOCTL(VM_UNBIND_PPTDEV, -	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS), +	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS | +	    VMMDEV_IOCTL_PRIV_CHECK_DRIVER), -	VMMDEV_IOCTL(VM_MAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS), -	VMMDEV_IOCTL(VM_UNMAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS), +	VMMDEV_IOCTL(VM_MAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS | +	    VMMDEV_IOCTL_PRIV_CHECK_DRIVER), +	VMMDEV_IOCTL(VM_UNMAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS | +	    VMMDEV_IOCTL_PRIV_CHECK_DRIVER),  #ifdef BHYVE_SNAPSHOT  #ifdef COMPAT_FREEBSD13  	VMMDEV_IOCTL(VM_SNAPSHOT_REQ_13, VMMDEV_IOCTL_LOCK_ALL_VCPUS), @@ -147,9 +151,9 @@ const struct vmmdev_ioctl vmmdev_machdep_ioctls[] = {  	VMMDEV_IOCTL(VM_LAPIC_LOCAL_IRQ, VMMDEV_IOCTL_MAYBE_ALLOC_VCPU), -	VMMDEV_IOCTL(VM_PPTDEV_MSI, 0), -	VMMDEV_IOCTL(VM_PPTDEV_MSIX, 0), -	VMMDEV_IOCTL(VM_PPTDEV_DISABLE_MSIX, 0), +	VMMDEV_IOCTL(VM_PPTDEV_MSI, VMMDEV_IOCTL_PRIV_CHECK_DRIVER), +	VMMDEV_IOCTL(VM_PPTDEV_MSIX, VMMDEV_IOCTL_PRIV_CHECK_DRIVER), +	VMMDEV_IOCTL(VM_PPTDEV_DISABLE_MSIX, VMMDEV_IOCTL_PRIV_CHECK_DRIVER),  	VMMDEV_IOCTL(VM_LAPIC_MSI, 0),  	VMMDEV_IOCTL(VM_IOAPIC_ASSERT_IRQ, 0),  	VMMDEV_IOCTL(VM_IOAPIC_DEASSERT_IRQ, 0), @@ -172,40 +176,13 @@ int  vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,      int fflag, struct thread *td)  { -	struct vm_seg_desc *vmsegdesc; -	struct vm_run *vmrun; -#ifdef COMPAT_FREEBSD13 -	struct vm_run_13 *vmrun_13; -#endif -	struct vm_exception *vmexc; -	struct vm_lapic_irq *vmirq; -	struct vm_lapic_msi *vmmsi; -	struct vm_ioapic_irq *ioapic_irq; -	struct vm_isa_irq *isa_irq; -	struct vm_isa_irq_trigger *isa_irq_trigger; -	struct vm_pptdev *pptdev; -	struct vm_pptdev_mmio *pptmmio; -	struct vm_pptdev_msi *pptmsi; -	struct vm_pptdev_msix *pptmsix; -	struct vm_x2apic *x2apic; -	struct vm_gpa_pte *gpapte; -	struct vm_gla2gpa *gg; -	struct vm_intinfo *vmii; -	struct vm_rtc_time *rtctime; -	struct vm_rtc_data *rtcdata; -	struct vm_readwrite_kernemu_device *kernemu; -#ifdef BHYVE_SNAPSHOT -	struct vm_snapshot_meta *snapshot_meta; -#ifdef COMPAT_FREEBSD13 -	struct vm_snapshot_meta_13 *snapshot_13; -#endif -#endif  	int error;  	error = 0;  	switch (cmd) {  	case VM_RUN: {  		struct vm_exit *vme; +		struct vm_run *vmrun;  		vmrun = (struct vm_run *)data;  		vme = vm_exitinfo(vcpu); @@ -243,6 +220,7 @@ vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,  	case VM_RUN_13: {  		struct vm_exit *vme;  		struct vm_exit_13 *vme_13; +		struct vm_run_13 *vmrun_13;  		vmrun_13 = (struct vm_run_13 *)data;  		vme_13 = &vmrun_13->vm_exit; @@ -281,85 +259,123 @@ vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,  		break;  	}  #endif -	case VM_PPTDEV_MSI: +	case VM_PPTDEV_MSI: { +		struct vm_pptdev_msi *pptmsi; +  		pptmsi = (struct vm_pptdev_msi *)data; -		error = ppt_setup_msi(vm, -				      pptmsi->bus, pptmsi->slot, pptmsi->func, -				      pptmsi->addr, pptmsi->msg, -				      pptmsi->numvec); +		error = ppt_setup_msi(vm, pptmsi->bus, pptmsi->slot, +		    pptmsi->func, pptmsi->addr, pptmsi->msg, pptmsi->numvec);  		break; -	case VM_PPTDEV_MSIX: +	} +	case VM_PPTDEV_MSIX: { +		struct vm_pptdev_msix *pptmsix; +  		pptmsix = (struct vm_pptdev_msix *)data; -		error = ppt_setup_msix(vm, -				       pptmsix->bus, pptmsix->slot, -				       pptmsix->func, pptmsix->idx, -				       pptmsix->addr, pptmsix->msg, -				       pptmsix->vector_control); +		error = ppt_setup_msix(vm, pptmsix->bus, pptmsix->slot, +		    pptmsix->func, pptmsix->idx, pptmsix->addr, pptmsix->msg, +		    pptmsix->vector_control);  		break; -	case VM_PPTDEV_DISABLE_MSIX: +	} +	case VM_PPTDEV_DISABLE_MSIX: { +		struct vm_pptdev *pptdev; +  		pptdev = (struct vm_pptdev *)data;  		error = ppt_disable_msix(vm, pptdev->bus, pptdev->slot, -					 pptdev->func); +		    pptdev->func);  		break; -	case VM_MAP_PPTDEV_MMIO: +	} +	case VM_MAP_PPTDEV_MMIO: { +		struct vm_pptdev_mmio *pptmmio; +  		pptmmio = (struct vm_pptdev_mmio *)data;  		error = ppt_map_mmio(vm, pptmmio->bus, pptmmio->slot, -				     pptmmio->func, pptmmio->gpa, pptmmio->len, -				     pptmmio->hpa); +		    pptmmio->func, pptmmio->gpa, pptmmio->len, pptmmio->hpa);  		break; -	case VM_UNMAP_PPTDEV_MMIO: +	} +	case VM_UNMAP_PPTDEV_MMIO: { +		struct vm_pptdev_mmio *pptmmio; +  		pptmmio = (struct vm_pptdev_mmio *)data;  		error = ppt_unmap_mmio(vm, pptmmio->bus, pptmmio->slot, -				       pptmmio->func, pptmmio->gpa, pptmmio->len); +		    pptmmio->func, pptmmio->gpa, pptmmio->len);  		break; -	case VM_BIND_PPTDEV: +	} +	case VM_BIND_PPTDEV: { +		struct vm_pptdev *pptdev; +  		pptdev = (struct vm_pptdev *)data;  		error = vm_assign_pptdev(vm, pptdev->bus, pptdev->slot, -					 pptdev->func); +		    pptdev->func);  		break; -	case VM_UNBIND_PPTDEV: +	} +	case VM_UNBIND_PPTDEV: { +		struct vm_pptdev *pptdev; +  		pptdev = (struct vm_pptdev *)data;  		error = vm_unassign_pptdev(vm, pptdev->bus, pptdev->slot, -					   pptdev->func); +		    pptdev->func);  		break; -	case VM_INJECT_EXCEPTION: +	} +	case VM_INJECT_EXCEPTION: { +		struct vm_exception *vmexc; +  		vmexc = (struct vm_exception *)data;  		error = vm_inject_exception(vcpu,  		    vmexc->vector, vmexc->error_code_valid, vmexc->error_code,  		    vmexc->restart_instruction);  		break; +	}  	case VM_INJECT_NMI:  		error = vm_inject_nmi(vcpu);  		break; -	case VM_LAPIC_IRQ: +	case VM_LAPIC_IRQ: { +		struct vm_lapic_irq *vmirq; +  		vmirq = (struct vm_lapic_irq *)data;  		error = lapic_intr_edge(vcpu, vmirq->vector);  		break; -	case VM_LAPIC_LOCAL_IRQ: +	} +	case VM_LAPIC_LOCAL_IRQ: { +		struct vm_lapic_irq *vmirq; +  		vmirq = (struct vm_lapic_irq *)data;  		error = lapic_set_local_intr(vm, vcpu, vmirq->vector);  		break; -	case VM_LAPIC_MSI: +	} +	case VM_LAPIC_MSI: { +		struct vm_lapic_msi *vmmsi; +  		vmmsi = (struct vm_lapic_msi *)data;  		error = lapic_intr_msi(vm, vmmsi->addr, vmmsi->msg);  		break; -	case VM_IOAPIC_ASSERT_IRQ: +	} +	case VM_IOAPIC_ASSERT_IRQ: { +		struct vm_ioapic_irq *ioapic_irq; +  		ioapic_irq = (struct vm_ioapic_irq *)data;  		error = vioapic_assert_irq(vm, ioapic_irq->irq);  		break; -	case VM_IOAPIC_DEASSERT_IRQ: +	} +	case VM_IOAPIC_DEASSERT_IRQ: { +		struct vm_ioapic_irq *ioapic_irq; +  		ioapic_irq = (struct vm_ioapic_irq *)data;  		error = vioapic_deassert_irq(vm, ioapic_irq->irq);  		break; -	case VM_IOAPIC_PULSE_IRQ: +	} +	case VM_IOAPIC_PULSE_IRQ: { +		struct vm_ioapic_irq *ioapic_irq; +  		ioapic_irq = (struct vm_ioapic_irq *)data;  		error = vioapic_pulse_irq(vm, ioapic_irq->irq);  		break; +	}  	case VM_IOAPIC_PINCOUNT:  		*(int *)data = vioapic_pincount(vm);  		break;  	case VM_SET_KERNEMU_DEV:  	case VM_GET_KERNEMU_DEV: { +		struct vm_readwrite_kernemu_device *kernemu;  		mem_region_write_t mwrite;  		mem_region_read_t mread;  		int size; @@ -396,60 +412,86 @@ vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,  			error = mread(vcpu, kernemu->gpa,  			    &kernemu->value, size, &arg);  		break; -		} -	case VM_ISA_ASSERT_IRQ: +	} +	case VM_ISA_ASSERT_IRQ: { +		struct vm_isa_irq *isa_irq; +  		isa_irq = (struct vm_isa_irq *)data;  		error = vatpic_assert_irq(vm, isa_irq->atpic_irq);  		if (error == 0 && isa_irq->ioapic_irq != -1)  			error = vioapic_assert_irq(vm, isa_irq->ioapic_irq);  		break; -	case VM_ISA_DEASSERT_IRQ: +	} +	case VM_ISA_DEASSERT_IRQ: { +		struct vm_isa_irq *isa_irq; +  		isa_irq = (struct vm_isa_irq *)data;  		error = vatpic_deassert_irq(vm, isa_irq->atpic_irq);  		if (error == 0 && isa_irq->ioapic_irq != -1)  			error = vioapic_deassert_irq(vm, isa_irq->ioapic_irq);  		break; -	case VM_ISA_PULSE_IRQ: +	} +	case VM_ISA_PULSE_IRQ: { +		struct vm_isa_irq *isa_irq; +  		isa_irq = (struct vm_isa_irq *)data;  		error = vatpic_pulse_irq(vm, isa_irq->atpic_irq);  		if (error == 0 && isa_irq->ioapic_irq != -1)  			error = vioapic_pulse_irq(vm, isa_irq->ioapic_irq);  		break; -	case VM_ISA_SET_IRQ_TRIGGER: +	} +	case VM_ISA_SET_IRQ_TRIGGER: { +		struct vm_isa_irq_trigger *isa_irq_trigger; +  		isa_irq_trigger = (struct vm_isa_irq_trigger *)data;  		error = vatpic_set_irq_trigger(vm,  		    isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger);  		break; -	case VM_SET_SEGMENT_DESCRIPTOR: +	} +	case VM_SET_SEGMENT_DESCRIPTOR: { +		struct vm_seg_desc *vmsegdesc; +  		vmsegdesc = (struct vm_seg_desc *)data; -		error = vm_set_seg_desc(vcpu, -					vmsegdesc->regnum, -					&vmsegdesc->desc); +		error = vm_set_seg_desc(vcpu, vmsegdesc->regnum, +		    &vmsegdesc->desc);  		break; -	case VM_GET_SEGMENT_DESCRIPTOR: +	} +	case VM_GET_SEGMENT_DESCRIPTOR: { +		struct vm_seg_desc *vmsegdesc; +  		vmsegdesc = (struct vm_seg_desc *)data; -		error = vm_get_seg_desc(vcpu, -					vmsegdesc->regnum, -					&vmsegdesc->desc); +		error = vm_get_seg_desc(vcpu, vmsegdesc->regnum, +		    &vmsegdesc->desc);  		break; -	case VM_SET_X2APIC_STATE: +	} +	case VM_SET_X2APIC_STATE: { +		struct vm_x2apic *x2apic; +  		x2apic = (struct vm_x2apic *)data;  		error = vm_set_x2apic_state(vcpu, x2apic->state);  		break; -	case VM_GET_X2APIC_STATE: +	} +	case VM_GET_X2APIC_STATE: { +		struct vm_x2apic *x2apic; +  		x2apic = (struct vm_x2apic *)data;  		error = vm_get_x2apic_state(vcpu, &x2apic->state);  		break; -	case VM_GET_GPA_PMAP: +	} +	case VM_GET_GPA_PMAP: { +		struct vm_gpa_pte *gpapte; +  		gpapte = (struct vm_gpa_pte *)data; -		pmap_get_mapping(vmspace_pmap(vm_vmspace(vm)), -				 gpapte->gpa, gpapte->pte, &gpapte->ptenum); -		error = 0; +		pmap_get_mapping(vmspace_pmap(vm_vmspace(vm)), gpapte->gpa, +		    gpapte->pte, &gpapte->ptenum);  		break; +	}  	case VM_GET_HPET_CAPABILITIES:  		error = vhpet_getcap((struct vm_hpet_cap *)data);  		break;  	case VM_GLA2GPA: { +		struct vm_gla2gpa *gg; +  		CTASSERT(PROT_READ == VM_PROT_READ);  		CTASSERT(PROT_WRITE == VM_PROT_WRITE);  		CTASSERT(PROT_EXEC == VM_PROT_EXECUTE); @@ -460,50 +502,76 @@ vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,  		    ("%s: vm_gla2gpa unknown error %d", __func__, error));  		break;  	} -	case VM_GLA2GPA_NOFAULT: +	case VM_GLA2GPA_NOFAULT: { +		struct vm_gla2gpa *gg; +  		gg = (struct vm_gla2gpa *)data;  		error = vm_gla2gpa_nofault(vcpu, &gg->paging, gg->gla,  		    gg->prot, &gg->gpa, &gg->fault);  		KASSERT(error == 0 || error == EFAULT,  		    ("%s: vm_gla2gpa unknown error %d", __func__, error));  		break; -	case VM_SET_INTINFO: +	} +	case VM_SET_INTINFO: { +		struct vm_intinfo *vmii; +  		vmii = (struct vm_intinfo *)data;  		error = vm_exit_intinfo(vcpu, vmii->info1);  		break; -	case VM_GET_INTINFO: +	} +	case VM_GET_INTINFO: { +		struct vm_intinfo *vmii; +  		vmii = (struct vm_intinfo *)data;  		error = vm_get_intinfo(vcpu, &vmii->info1, &vmii->info2);  		break; -	case VM_RTC_WRITE: +	} +	case VM_RTC_WRITE: { +		struct vm_rtc_data *rtcdata; +  		rtcdata = (struct vm_rtc_data *)data;  		error = vrtc_nvram_write(vm, rtcdata->offset,  		    rtcdata->value);  		break; -	case VM_RTC_READ: +	} +	case VM_RTC_READ: { +		struct vm_rtc_data *rtcdata; +  		rtcdata = (struct vm_rtc_data *)data;  		error = vrtc_nvram_read(vm, rtcdata->offset,  		    &rtcdata->value);  		break; -	case VM_RTC_SETTIME: +	} +	case VM_RTC_SETTIME: { +		struct vm_rtc_time *rtctime; +  		rtctime = (struct vm_rtc_time *)data;  		error = vrtc_set_time(vm, rtctime->secs);  		break; -	case VM_RTC_GETTIME: -		error = 0; +	} +	case VM_RTC_GETTIME: { +		struct vm_rtc_time *rtctime; +  		rtctime = (struct vm_rtc_time *)data;  		rtctime->secs = vrtc_get_time(vm);  		break; +	}  	case VM_RESTART_INSTRUCTION:  		error = vm_restart_instruction(vcpu);  		break;  #ifdef BHYVE_SNAPSHOT -	case VM_SNAPSHOT_REQ: +	case VM_SNAPSHOT_REQ: { +		struct vm_snapshot_meta *snapshot_meta; +  		snapshot_meta = (struct vm_snapshot_meta *)data;  		error = vm_snapshot_req(vm, snapshot_meta);  		break; +	}  #ifdef COMPAT_FREEBSD13 -	case VM_SNAPSHOT_REQ_13: +	case VM_SNAPSHOT_REQ_13: { +		struct vm_snapshot_meta *snapshot_meta; +		struct vm_snapshot_meta_13 *snapshot_13; +  		/*  		 * The old structure just has an additional pointer at  		 * the start that is ignored. @@ -513,6 +581,7 @@ vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,  		    (struct vm_snapshot_meta *)&snapshot_13->dev_data;  		error = vm_snapshot_req(vm, snapshot_meta);  		break; +	}  #endif  	case VM_RESTORE_TIME:  		error = vm_restore_time(vm); diff --git a/sys/amd64/vmm/vmm_mem.h b/sys/amd64/vmm/vmm_mem.h index 41b9bf07c4fc..d905fd37001d 100644 --- a/sys/amd64/vmm/vmm_mem.h +++ b/sys/amd64/vmm/vmm_mem.h @@ -30,10 +30,9 @@  #define	_VMM_MEM_H_  struct vmspace; -struct vm_object; -struct vm_object *vmm_mmio_alloc(struct vmspace *, vm_paddr_t gpa, size_t len, -				 vm_paddr_t hpa); +int		vmm_mmio_alloc(struct vmspace *, vm_paddr_t gpa, size_t len, +		    vm_paddr_t hpa);  void		vmm_mmio_free(struct vmspace *, vm_paddr_t gpa, size_t size);  vm_paddr_t	vmm_mem_maxaddr(void); diff --git a/sys/amd64/vmm/vmm_mem_machdep.c b/sys/amd64/vmm/vmm_mem_machdep.c index e96c9e4bdc66..afb3a0274e2a 100644 --- a/sys/amd64/vmm/vmm_mem_machdep.c +++ b/sys/amd64/vmm/vmm_mem_machdep.c @@ -36,6 +36,7 @@  #include <vm/vm.h>  #include <vm/vm_param.h>  #include <vm/pmap.h> +#include <vm/vm_extern.h>  #include <vm/vm_map.h>  #include <vm/vm_object.h>  #include <vm/vm_page.h> @@ -45,40 +46,48 @@  #include "vmm_mem.h" -vm_object_t +int  vmm_mmio_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len, -	       vm_paddr_t hpa) +    vm_paddr_t hpa)  { -	int error; -	vm_object_t obj;  	struct sglist *sg; +	vm_object_t obj; +	int error; + +	if (gpa + len < gpa || hpa + len < hpa || (gpa & PAGE_MASK) != 0 || +	    (hpa & PAGE_MASK) != 0 || (len & PAGE_MASK) != 0) +		return (EINVAL);  	sg = sglist_alloc(1, M_WAITOK);  	error = sglist_append_phys(sg, hpa, len);  	KASSERT(error == 0, ("error %d appending physaddr to sglist", error));  	obj = vm_pager_allocate(OBJT_SG, sg, len, VM_PROT_RW, 0, NULL); -	if (obj != NULL) { -		/* -		 * VT-x ignores the MTRR settings when figuring out the -		 * memory type for translations obtained through EPT. -		 * -		 * Therefore we explicitly force the pages provided by -		 * this object to be mapped as uncacheable. -		 */ -		VM_OBJECT_WLOCK(obj); -		error = vm_object_set_memattr(obj, VM_MEMATTR_UNCACHEABLE); -		VM_OBJECT_WUNLOCK(obj); -		if (error != KERN_SUCCESS) { -			panic("vmm_mmio_alloc: vm_object_set_memattr error %d", -				error); -		} -		error = vm_map_find(&vmspace->vm_map, obj, 0, &gpa, len, 0, -				    VMFS_NO_SPACE, VM_PROT_RW, VM_PROT_RW, 0); -		if (error != KERN_SUCCESS) { -			vm_object_deallocate(obj); -			obj = NULL; -		} +	if (obj == NULL) +		return (ENOMEM); + +	/* +	 * VT-x ignores the MTRR settings when figuring out the memory type for +	 * translations obtained through EPT. +	 * +	 * Therefore we explicitly force the pages provided by this object to be +	 * mapped as uncacheable. +	 */ +	VM_OBJECT_WLOCK(obj); +	error = vm_object_set_memattr(obj, VM_MEMATTR_UNCACHEABLE); +	VM_OBJECT_WUNLOCK(obj); +	if (error != KERN_SUCCESS) +		panic("vmm_mmio_alloc: vm_object_set_memattr error %d", error); + +	vm_map_lock(&vmspace->vm_map); +	error = vm_map_insert(&vmspace->vm_map, obj, 0, gpa, gpa + len, +	    VM_PROT_RW, VM_PROT_RW, 0); +	vm_map_unlock(&vmspace->vm_map); +	if (error != KERN_SUCCESS) { +		error = vm_mmap_to_errno(error); +		vm_object_deallocate(obj); +	} else { +		error = 0;  	}  	/* @@ -94,7 +103,7 @@ vmm_mmio_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len,  	 */  	sglist_free(sg); -	return (obj); +	return (error);  }  void | 
