vmm/vmd: add io instruction length to exit information.
authordv <dv@openbsd.org>
Wed, 10 Jan 2024 04:13:59 +0000 (04:13 +0000)
committerdv <dv@openbsd.org>
Wed, 10 Jan 2024 04:13:59 +0000 (04:13 +0000)
Add the instruction length to the vm exit information to allower
vmd(8) to manipulate the instruction pointer after io emulation.
This is preparation for emulating string-based io instructions.

Removes the instruction pointer update from the kernel (vmm(4)) as
well as the instruction length checks, which were overly restrictive
anyways based on the way prefixes work in x86 instructions.

ok mlarkin@

sys/arch/amd64/amd64/vmm_machdep.c
sys/arch/amd64/include/vmmvar.h
usr.sbin/vmd/vm.c

index eafbcf8..0be59cb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm_machdep.c,v 1.13 2024/01/06 13:17:20 dv Exp $ */
+/* $OpenBSD: vmm_machdep.c,v 1.14 2024/01/10 04:13:59 dv Exp $ */
 /*
  * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -3989,6 +3989,13 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp)
                        if (vcpu->vc_exit.vei.vei_dir == VEI_DIR_IN)
                                vcpu->vc_gueststate.vg_rax =
                                    vcpu->vc_exit.vei.vei_data;
+                       vcpu->vc_gueststate.vg_rip =
+                           vcpu->vc_exit.vrs.vrs_gprs[VCPU_REGS_RIP];
+                       if (vmwrite(VMCS_GUEST_IA32_RIP,
+                           vcpu->vc_gueststate.vg_rip)) {
+                               printf("%s: failed to update rip\n", __func__);
+                               return (EINVAL);
+                       }
                        break;
                case VMX_EXIT_EPT_VIOLATION:
                        ret = vcpu_writeregs_vmx(vcpu, VM_RWREGS_GPRS, 0,
@@ -4525,7 +4532,6 @@ svm_handle_exit(struct vcpu *vcpu)
        case SVM_VMEXIT_IOIO:
                if (svm_handle_inout(vcpu) == 0)
                        ret = EAGAIN;
-               update_rip = 1;
                break;
        case SVM_VMEXIT_HLT:
                ret = svm_handle_hlt(vcpu);
@@ -4610,7 +4616,6 @@ vmx_handle_exit(struct vcpu *vcpu)
        case VMX_EXIT_IO:
                if (vmx_handle_inout(vcpu) == 0)
                        ret = EAGAIN;
-               update_rip = 1;
                break;
        case VMX_EXIT_EXTINT:
                vmx_handle_intr(vcpu);
@@ -5159,12 +5164,6 @@ svm_handle_inout(struct vcpu *vcpu)
        struct vmcb *vmcb = (struct vmcb *)vcpu->vc_control_va;
 
        insn_length = vmcb->v_exitinfo2 - vmcb->v_rip;
-       if (insn_length != 1 && insn_length != 2) {
-               DPRINTF("%s: IN/OUT instruction with length %lld not "
-                   "supported\n", __func__, insn_length);
-               return (EINVAL);
-       }
-
        exit_qual = vmcb->v_exitinfo1;
 
        /* Bit 0 - direction */
@@ -5190,11 +5189,11 @@ svm_handle_inout(struct vcpu *vcpu)
        /* Data */
        vcpu->vc_exit.vei.vei_data = vmcb->v_rax;
 
+       vcpu->vc_exit.vei.vei_insn_len = (uint8_t)insn_length;
+
        TRACEPOINT(vmm, inout, vcpu, vcpu->vc_exit.vei.vei_port,
            vcpu->vc_exit.vei.vei_dir, vcpu->vc_exit.vei.vei_data);
 
-       vcpu->vc_gueststate.vg_rip += insn_length;
-
        return (0);
 }
 
@@ -5220,12 +5219,6 @@ vmx_handle_inout(struct vcpu *vcpu)
                return (EINVAL);
        }
 
-       if (insn_length != 1 && insn_length != 2) {
-               DPRINTF("%s: IN/OUT instruction with length %lld not "
-                   "supported\n", __func__, insn_length);
-               return (EINVAL);
-       }
-
        if (vmx_get_exit_qualification(&exit_qual)) {
                printf("%s: can't get exit qual\n", __func__);
                return (EINVAL);
@@ -5249,11 +5242,11 @@ vmx_handle_inout(struct vcpu *vcpu)
        /* Data */
        vcpu->vc_exit.vei.vei_data = (uint32_t)vcpu->vc_gueststate.vg_rax;
 
+       vcpu->vc_exit.vei.vei_insn_len = (uint8_t)insn_length;
+
        TRACEPOINT(vmm, inout, vcpu, vcpu->vc_exit.vei.vei_port,
            vcpu->vc_exit.vei.vei_dir, vcpu->vc_exit.vei.vei_data);
 
-       vcpu->vc_gueststate.vg_rip += insn_length;
-
        return (0);
 }
 
@@ -6416,6 +6409,9 @@ vcpu_run_svm(struct vcpu *vcpu, struct vm_run_params *vrp)
                                    vcpu->vc_exit.vei.vei_data;
                                vmcb->v_rax = vcpu->vc_gueststate.vg_rax;
                        }
+                       vcpu->vc_gueststate.vg_rip =
+                           vcpu->vc_exit.vrs.vrs_gprs[VCPU_REGS_RIP];
+                       vmcb->v_rip = vcpu->vc_gueststate.vg_rip;
                        break;
                case SVM_VMEXIT_NPF:
                        ret = vcpu_writeregs_svm(vcpu, VM_RWREGS_GPRS,
index 5f66201..a013189 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vmmvar.h,v 1.96 2024/01/06 13:17:20 dv Exp $  */
+/*     $OpenBSD: vmmvar.h,v 1.97 2024/01/10 04:13:59 dv Exp $  */
 /*
  * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -338,6 +338,7 @@ struct vm_exit_inout {
        uint8_t                 vei_encoding;   /* operand encoding */
        uint16_t                vei_port;       /* port */
        uint32_t                vei_data;       /* data */
+       uint8_t                 vei_insn_len;   /* Count of instruction bytes */
 };
 /*
  *  vm_exit_eptviolation       : describes an EPT VIOLATION exit
index ee31c42..cc2b4fc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vm.c,v 1.94 2023/09/26 01:53:54 dv Exp $      */
+/*     $OpenBSD: vm.c,v 1.95 2024/01/10 04:13:59 dv Exp $      */
 
 /*
  * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -1750,6 +1750,8 @@ vcpu_exit_inout(struct vm_run_params *vrp)
        else if (vei->vei.vei_dir == VEI_DIR_IN)
                set_return_data(vei, 0xFFFFFFFF);
 
+       vei->vrs.vrs_gprs[VCPU_REGS_RIP] += vei->vei.vei_insn_len;
+
        if (intr != 0xFF)
                vcpu_assert_pic_irq(vrp->vrp_vm_id, vrp->vrp_vcpu_id, intr);
 }