ping...would like to get this in if possible so I can move onto fixing
some things in vmm.

Dave Voutila <d...@sisu.io> writes:

> tech@,
>
> Continuing my vmm/vmd bug hunt, the following diff adapts
> vcpu_readregs_vmx to optionally load the vmcs on the current cpu. This
> has gone unnoticed as the ioctl isn't used in typical vmd usage and the
> usage of vcpu_readregs_vmx in the run ioctl is after the vmcs is already
> loaded on the current cpu.
>
> This fixes `vmctl send` on Intel hosts. (A fix for `vmctl receive` comes
> next.)
>
> Currently, `vmctl send` tries to serialize the vcpu registers as part of
> serializing the vm state. On an MP machine, it's highly probable that
> the vmread instructions will fail as they'll be executed on a cpu that
> doesn't have the vmcs loaded.
>
> While here, I noticed the vcpu_writeregs_vmx function doesn't set the
> vcpu's vmcs state variable to VMCS_CLEARED after running vmclear. This
> can cause failure to vm-enter as vmm uses that state to determine which
> of the two Intel instructions to call (vmlaunch or vmresume).
>
> ok?
>
> -dv
>
> Index: sys/arch/amd64/amd64/vmm.c
> ===================================================================
> RCS file: /opt/cvs/src/sys/arch/amd64/amd64/vmm.c,v
> retrieving revision 1.308
> diff -u -p -r1.308 vmm.c
> --- sys/arch/amd64/amd64/vmm.c        4 May 2022 02:24:26 -0000       1.308
> +++ sys/arch/amd64/amd64/vmm.c        8 May 2022 18:37:42 -0000
> @@ -140,7 +140,7 @@ int vm_rwregs(struct vm_rwregs_params *,
>  int vm_mprotect_ept(struct vm_mprotect_ept_params *);
>  int vm_rwvmparams(struct vm_rwvmparams_params *, int);
>  int vm_find(uint32_t, struct vm **);
> -int vcpu_readregs_vmx(struct vcpu *, uint64_t, struct vcpu_reg_state *);
> +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 
> *);
>  int vcpu_writeregs_svm(struct vcpu *, uint64_t, struct vcpu_reg_state *);
> @@ -978,7 +978,7 @@ vm_rwregs(struct vm_rwregs_params *vrwp,
>       if (vmm_softc->mode == VMM_MODE_VMX ||
>           vmm_softc->mode == VMM_MODE_EPT)
>               ret = (dir == 0) ?
> -                 vcpu_readregs_vmx(vcpu, vrwp->vrwp_mask, vrs) :
> +                 vcpu_readregs_vmx(vcpu, vrwp->vrwp_mask, 1, vrs) :
>                   vcpu_writeregs_vmx(vcpu, vrwp->vrwp_mask, 1, vrs);
>       else if (vmm_softc->mode == VMM_MODE_SVM ||
>           vmm_softc->mode == VMM_MODE_RVI)
> @@ -1986,6 +1986,7 @@ vcpu_reload_vmcs_vmx(struct vcpu *vcpu)
>   * Parameters:
>   *  vcpu: the vcpu to read register values from
>   *  regmask: the types of registers to read
> + *  loadvmcs: bit to indicate whether the VMCS has to be loaded first
>   *  vrs: output parameter where register values are stored
>   *
>   * Return values:
> @@ -1993,7 +1994,7 @@ vcpu_reload_vmcs_vmx(struct vcpu *vcpu)
>   *  EINVAL: an error reading registers occurred
>   */
>  int
> -vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask,
> +vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask, int loadvmcs,
>      struct vcpu_reg_state *vrs)
>  {
>       int i, ret = 0;
> @@ -2005,6 +2006,11 @@ vcpu_readregs_vmx(struct vcpu *vcpu, uin
>       struct vcpu_segment_info *sregs = vrs->vrs_sregs;
>       struct vmx_msr_store *msr_store;
>
> +     if (loadvmcs) {
> +             if (vcpu_reload_vmcs_vmx(vcpu))
> +                     return (EINVAL);
> +     }
> +
>  #ifdef VMM_DEBUG
>       /* VMCS should be loaded... */
>       paddr_t pa = 0ULL;
> @@ -2393,6 +2399,7 @@ out:
>       if (loadvmcs) {
>               if (vmclear(&vcpu->vc_control_pa))
>                       ret = EINVAL;
> +             atomic_swap_uint(&vcpu->vc_vmx_vmcs_state, VMCS_CLEARED);
>       }
>       return (ret);
>  }
> @@ -4631,7 +4638,7 @@ vmm_translate_gva(struct vcpu *vcpu, uin
>
>       if (vmm_softc->mode == VMM_MODE_EPT ||
>           vmm_softc->mode == VMM_MODE_VMX) {
> -             if (vcpu_readregs_vmx(vcpu, VM_RWREGS_ALL, &vrs))
> +             if (vcpu_readregs_vmx(vcpu, VM_RWREGS_ALL, 1, &vrs))
>                       return (EINVAL);
>       } else if (vmm_softc->mode == VMM_MODE_RVI ||
>           vmm_softc->mode == VMM_MODE_SVM) {
> @@ -5111,7 +5118,7 @@ vcpu_run_vmx(struct vcpu *vcpu, struct v
>       vcpu->vc_last_pcpu = curcpu();
>
>       /* Copy the VCPU register state to the exit structure */
> -     if (vcpu_readregs_vmx(vcpu, VM_RWREGS_ALL, &vcpu->vc_exit.vrs))
> +     if (vcpu_readregs_vmx(vcpu, VM_RWREGS_ALL, 0, &vcpu->vc_exit.vrs))
>               ret = EINVAL;
>       vcpu->vc_exit.cpl = vmm_get_guest_cpu_cpl(vcpu);


--
-Dave Voutila

Reply via email to