-/* $OpenBSD: vmm.c,v 1.320 2022/08/30 17:09:21 dv Exp $ */
+/* $OpenBSD: vmm.c,v 1.321 2022/09/01 22:01:40 dv Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
update_rip = 1;
break;
case SVM_VMEXIT_IOIO:
- ret = svm_handle_inout(vcpu);
+ if (svm_handle_inout(vcpu) == 0)
+ ret = EAGAIN;
update_rip = 1;
break;
case SVM_VMEXIT_HLT:
update_rip = 1;
break;
case VMX_EXIT_IO:
- ret = vmx_handle_inout(vcpu);
+ if (vmx_handle_inout(vcpu) == 0)
+ ret = EAGAIN;
update_rip = 1;
break;
case VMX_EXIT_EXTINT:
*
* Exit handler for IN/OUT instructions.
*
- * The vmm can handle certain IN/OUTS without exiting to vmd, but most of these
- * will be passed to vmd for completion.
- *
* Parameters:
* vcpu: The VCPU where the IN/OUT instruction occurred
*
* Return values:
* 0: if successful
* EINVAL: an invalid IN/OUT instruction was encountered
- * EAGAIN: return to vmd - more processing needed in userland
*/
int
svm_handle_inout(struct vcpu *vcpu)
{
uint64_t insn_length, exit_qual;
- int ret;
struct vmcb *vmcb = (struct vmcb *)vcpu->vc_control_va;
insn_length = vmcb->v_exitinfo2 - vmcb->v_rip;
exit_qual = vmcb->v_exitinfo1;
/* Bit 0 - direction */
- vcpu->vc_exit.vei.vei_dir = (exit_qual & 0x1);
+ if (exit_qual & 0x1)
+ vcpu->vc_exit.vei.vei_dir = VEI_DIR_IN;
+ else
+ vcpu->vc_exit.vei.vei_dir = VEI_DIR_OUT;
/* Bit 2 - string instruction? */
vcpu->vc_exit.vei.vei_string = (exit_qual & 0x4) >> 2;
/* Bit 3 - REP prefix? */
vcpu->vc_gueststate.vg_rip += insn_length;
- /*
- * The following ports usually belong to devices owned by vmd.
- * Return EAGAIN to signal help needed from userspace (vmd).
- * Return 0 to indicate we don't care about this port.
- *
- * XXX something better than a hardcoded list here, maybe
- * configure via vmd via the device list in vm create params?
- */
- switch (vcpu->vc_exit.vei.vei_port) {
- case IO_ICU1 ... IO_ICU1 + 1:
- case 0x40 ... 0x43:
- case PCKBC_AUX:
- case IO_RTC ... IO_RTC + 1:
- case IO_ICU2 ... IO_ICU2 + 1:
- case 0x3f8 ... 0x3ff:
- case ELCR0 ... ELCR1:
- case 0x500 ... 0x511:
- case 0x514:
- case 0x518:
- case 0xcf8:
- case 0xcfc ... 0xcff:
- case VMM_PCI_IO_BAR_BASE ... VMM_PCI_IO_BAR_END:
- ret = EAGAIN;
- break;
- default:
- /* Read from unsupported ports returns FFs */
- if (vcpu->vc_exit.vei.vei_dir == 1) {
- switch(vcpu->vc_exit.vei.vei_size) {
- case 1:
- vcpu->vc_gueststate.vg_rax |= 0xFF;
- vmcb->v_rax |= 0xFF;
- break;
- case 2:
- vcpu->vc_gueststate.vg_rax |= 0xFFFF;
- vmcb->v_rax |= 0xFFFF;
- break;
- case 4:
- vcpu->vc_gueststate.vg_rax |= 0xFFFFFFFF;
- vmcb->v_rax |= 0xFFFFFFFF;
- break;
- }
- }
- ret = 0;
- }
-
- return (ret);
+ return (0);
}
/*
*
* Exit handler for IN/OUT instructions.
*
- * The vmm can handle certain IN/OUTS without exiting to vmd, but most of these
- * will be passed to vmd for completion.
+ * Parameters:
+ * vcpu: The VCPU where the IN/OUT instruction occurred
+ *
+ * Return values:
+ * 0: if successful
+ * EINVAL: invalid IN/OUT instruction or vmread failures occurred
*/
int
vmx_handle_inout(struct vcpu *vcpu)
{
uint64_t insn_length, exit_qual;
- int ret;
if (vmread(VMCS_INSTRUCTION_LENGTH, &insn_length)) {
printf("%s: can't obtain instruction length\n", __func__);
/* Bits 0:2 - size of exit */
vcpu->vc_exit.vei.vei_size = (exit_qual & 0x7) + 1;
/* Bit 3 - direction */
- vcpu->vc_exit.vei.vei_dir = (exit_qual & 0x8) >> 3;
+ if ((exit_qual & 0x8) >> 3)
+ vcpu->vc_exit.vei.vei_dir = VEI_DIR_IN;
+ else
+ vcpu->vc_exit.vei.vei_dir = VEI_DIR_OUT;
/* Bit 4 - string instruction? */
vcpu->vc_exit.vei.vei_string = (exit_qual & 0x10) >> 4;
/* Bit 5 - REP prefix? */
vcpu->vc_gueststate.vg_rip += insn_length;
- /*
- * The following ports usually belong to devices owned by vmd.
- * Return EAGAIN to signal help needed from userspace (vmd).
- * Return 0 to indicate we don't care about this port.
- *
- * XXX something better than a hardcoded list here, maybe
- * configure via vmd via the device list in vm create params?
- */
- switch (vcpu->vc_exit.vei.vei_port) {
- case IO_ICU1 ... IO_ICU1 + 1:
- case 0x40 ... 0x43:
- case PCKBC_AUX:
- case IO_RTC ... IO_RTC + 1:
- case IO_ICU2 ... IO_ICU2 + 1:
- case 0x3f8 ... 0x3ff:
- case ELCR0 ... ELCR1:
- case 0x500 ... 0x511:
- case 0x514:
- case 0x518:
- case 0xcf8:
- case 0xcfc ... 0xcff:
- case VMM_PCI_IO_BAR_BASE ... VMM_PCI_IO_BAR_END:
- ret = EAGAIN;
- break;
- default:
- /* Read from unsupported ports returns FFs */
- if (vcpu->vc_exit.vei.vei_dir == VEI_DIR_IN) {
- if (vcpu->vc_exit.vei.vei_size == 4)
- vcpu->vc_gueststate.vg_rax |= 0xFFFFFFFF;
- else if (vcpu->vc_exit.vei.vei_size == 2)
- vcpu->vc_gueststate.vg_rax |= 0xFFFF;
- else if (vcpu->vc_exit.vei.vei_size == 1)
- vcpu->vc_gueststate.vg_rax |= 0xFF;
- }
- ret = 0;
- }
-
- return (ret);
+ return (0);
}
/*