From cc847d2a3263780417a92f93f643d708768ba82e Mon Sep 17 00:00:00 2001 From: dv Date: Wed, 10 Jan 2024 04:13:59 +0000 Subject: [PATCH] vmm/vmd: add io instruction length to exit information. 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 | 34 +++++++++++++----------------- sys/arch/amd64/include/vmmvar.h | 3 ++- usr.sbin/vmd/vm.c | 4 +++- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c index eafbcf8fafc..0be59cb4466 100644 --- a/sys/arch/amd64/amd64/vmm_machdep.c +++ b/sys/arch/amd64/amd64/vmm_machdep.c @@ -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 * @@ -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, diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h index 5f662010e69..a0131892ef4 100644 --- a/sys/arch/amd64/include/vmmvar.h +++ b/sys/arch/amd64/include/vmmvar.h @@ -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 * @@ -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 diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index ee31c42cfbb..cc2b4fc7636 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -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 @@ -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); } -- 2.20.1