[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] SVM: re-work VMCB sync-ing
On 26/04/18 13:01, Jan Beulich wrote: > While the main problem to be addressed here is the issue of what so far > was named "vmcb_in_sync" starting out with the wrong value (should have > been true instead of false, to prevent performing a VMSAVE without ever > having VMLOADed the vCPU's state), go a step further and make the > sync-ed state a tristate: CPU and memory may be in sync or an update > may be required in either direction. Rename the field and introduce an > enum. Callers of svm_sync_vmcb() now indicate the intended new state. > With that, there's no need to VMLOAD the state perhaps multiple times; > all that's needed is loading it once before VM entry. > > Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> > --- > I've been considering to put the VMLOAD invocation in > svm_asid_handle_vmrun() (instead of the two copies in svm_do_resume() > and svm_vmexit_handler()), but that seemed a little too abusive of the > function. Perhaps a more general helper function would be wanted, but > perhaps that's something to be done when we've decided whether to put > both VMSAVE and VMLOAD inside the CLGI protected region. > I'm also not really certain about svm_vmexit_do_vmload(): All I'm doing > here is a 1:1 change from previous behavior, but I'm unconvinced this > was/is really correct. FWIW, In my not-yet-complete patch for the issue, I'd gone with @@ -90,7 +91,14 @@ UNLIKELY_END(svm_trace) pop %r13 pop %r12 pop %rbp + mov VCPU_svm_vmcb_pa(%rbx),%rax + cmpb $0, VCPU_svm_vmload_needed(%rbx) + je 1f + VMLOAD + movb $0, VCPU_svm_vmload_needed(%rbx) +1: + pop %rbx pop %r11 pop %r10 (albeit with a slightly different state structure) and was considering putting the VMLOAD in an unlikely section to get the static prediction the correct way around. > --- a/xen/arch/x86/hvm/svm/svm.c > +++ b/xen/arch/x86/hvm/svm/svm.c > @@ -680,16 +680,15 @@ static void svm_cpuid_policy_changed(str > cp->extd.ibpb ? MSR_INTERCEPT_NONE : MSR_INTERCEPT_RW); > } > > -static void svm_sync_vmcb(struct vcpu *v) > +static void svm_sync_vmcb(struct vcpu *v, enum vmcb_sync_state new_state) > { > struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; > > - if ( arch_svm->vmcb_in_sync ) > - return; > - > - arch_svm->vmcb_in_sync = 1; > + if ( arch_svm->vmcb_sync_state == vmcb_needs_vmsave ) > + svm_vmsave(arch_svm->vmcb); > > - svm_vmsave(arch_svm->vmcb); > + if ( arch_svm->vmcb_sync_state != vmcb_needs_vmload ) > + arch_svm->vmcb_sync_state = new_state; This is slightly awkward for a couple of reasons. First, passing vmcb_in_sync in forget the fact that a vmload is needed. In my patch, I introduced svm_sync_vmcb_for_update(), rather than requiring a parameter to be passed in. I think this is a better API, and it shrinks the size of the patch. Also, we currently need segment register codepaths to work from non-current context, and will very shortly want the MSR paths to do the same. By putting an ASSERT(v == current) beside the svm_vmsave(arch_svm->vmcb), we can drop the (v == current) check in the callers, and catch corner cases where state isn't in sync for a remote update. > @@ -1086,7 +1079,7 @@ static void svm_ctxt_switch_from(struct > svm_lwp_save(v); > svm_tsc_ratio_save(v); > > - svm_sync_vmcb(v); > + svm_sync_vmcb(v, vmcb_needs_vmload); > svm_vmload_pa(per_cpu(host_vmcb, cpu)); > > /* Resume use of ISTs now that the host TR is reinstated. */ > @@ -1114,7 +1107,6 @@ static void svm_ctxt_switch_to(struct vc > svm_restore_dr(v); > > svm_vmsave_pa(per_cpu(host_vmcb, cpu)); As an observation, this vmsave isn't needed. All state in host_vmcb is either constant after the AP bringup-path, or loaded properly in the PV ctxt_switch_to() path. This can be some future perf improvements though. > - svm_vmload(vmcb); > vmcb->cleanbits.bytes = 0; > svm_lwp_load(v); > svm_tsc_ratio_load(v); > --- a/xen/include/asm-x86/hvm/svm/vmcb.h > +++ b/xen/include/asm-x86/hvm/svm/vmcb.h > @@ -495,12 +495,19 @@ struct vmcb_struct { > struct svm_domain { > }; > > +enum vmcb_sync_state { > + vmcb_in_sync, > + vmcb_needs_vmsave, /* VMCB out of sync (VMSAVE needed)? */ > + vmcb_needs_vmload /* VMCB dirty (VMLOAD needed)? */ > +}; If I were you, I'd go with enum vmcb_sync_state { vmcb_needs_vmsave, vmcb_in_sync, vmcb_needs_vmload, }; So it numerically follows the logical progression. > + > struct arch_svm_struct { > struct vmcb_struct *vmcb; > u64 vmcb_pa; > unsigned long *msrpm; > int launch_core; > - bool_t vmcb_in_sync; /* VMCB sync'ed with VMSAVE? */ > + /* * VMRUN doesn't switch fs/gs/tr/ldtr and SHADOWGS/SYSCALL/SYSENTER state. * Therefore, guest state is in the hardware registers when servicing a * VMExit. * * Immediately after a VMExit, the vmcb is stale, and needs to be brought * into sync by VMSAVE. If state in the vmcb is modified, a VMLOAD is * needed before the following VMRUN. */ ~Andrew > + uint8_t vmcb_sync_state; /* enum vmcb_sync_state */ > > /* VMCB has a cached instruction from #PF/#NPF Decode Assist? */ > uint8_t cached_insn_len; /* Zero if no cached instruction. */ > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |