Radim Krčmář <rkrc...@redhat.com> writes:

> 2018-03-12 15:19+0100, Vitaly Kuznetsov:
>> 
>> That said I'd like to defer the question to KVM maintainers: Paolo,
>> Radim, what would you like me to do? Use STATIC_JUMP_IF_TRUE/FALSE as
>> they are, try to make them work for !HAVE_JUMP_LABEL and use them or
>> maybe we can commit the series as-is and have it as a future
>> optimization (e.g. when HAVE_JUMP_LABEL becomes mandatory)?
>
> Please take a look into making a macro that uses STATIC_JUMP_IF_FALSE or
> reads the value from provided static_key and does a test-jump, depending
> on HAVE_JUMP_LABEL.
> It doesn't need to be suited for general use, just something that moves
> the ugliness away from vmx_vcpu_run.
> (Although having it in jump_label.h would be great. I think the main
>  obstacle is clobbering of flags.)
>

The other problem is that we actually have inline assembly and I'm not
sure how to use .macros from '#ifdef __ASSEMBLY__' sections there ...

anyway, I tried using the jump label magic and I ended up with the
following:

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 44b6efa7d54e..fb15ccf260fb 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -9932,10 +9932,26 @@ static void vmx_arm_hv_timer(struct kvm_vcpu *vcpu)
        vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc);
 }
 
+#ifdef HAVE_JUMP_LABEL
+#define STATIC_CHECK_EVMCS_INUSE(label, key)                           \
+       ".Lstatic_evmcs:\n\t"                                           \
+       ".byte 0xe9\n\t"                                                \
+       ".long " #label " - .Lstatic_evmcs_after\n\t"                   \
+       ".Lstatic_evmcs_after:\n"                                       \
+       ".pushsection __jump_table,  \"aw\" \n\t"                       \
+       _ASM_ALIGN "\n\t"                                               \
+       _ASM_PTR ".Lstatic_evmcs, " #label ", %c[" #key "] + 1 \n\t"    \
+       ".popsection \n\t"
+#else
+#define STATIC_CHECK_EVMCS_INUSE(label, key)                           \
+       "cmpl $0, (%c[" #key "])\n\t"                                   \
+       "je " #label "\n\t"
+#endif
+
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       unsigned long cr3, cr4, evmcs_rsp;
+       unsigned long cr3, cr4;
 
        /* Record the guest's net vcpu time for enforced NMI injections. */
        if (unlikely(!enable_vnmi &&
@@ -10002,9 +10018,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu 
*vcpu)
 
        vmx->__launched = vmx->loaded_vmcs->launched;
 
-       evmcs_rsp = static_branch_unlikely(&enable_evmcs) ?
-               (unsigned long)&current_evmcs->host_rsp : 0;
-
        asm(
                /* Store host registers */
                "push %%" _ASM_DX "; push %%" _ASM_BP ";"
@@ -10013,12 +10026,11 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu 
*vcpu)
                "cmp %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
                "je 1f \n\t"
                "mov %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
-               /* Avoid VMWRITE when Enlightened VMCS is in use */
-               "test %%" _ASM_SI ", %%" _ASM_SI " \n\t"
-               "jz 2f \n\t"
-               "mov %%" _ASM_SP ", (%%" _ASM_SI ") \n\t"
+               /* Avoid VMWRITE to HOST_SP when Enlightened VMCS is in use */
+               STATIC_CHECK_EVMCS_INUSE(.Lvmwrite_sp, enable_evmcs)
+               "mov %%" _ASM_SP ", %c[evmcs_hrsp](%2) \n\t"
                "jmp 1f \n\t"
-               "2: \n\t"
+               ".Lvmwrite_sp: \n\t"
                __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
                "1: \n\t"
                /* Reload cr2 if changed */
@@ -10096,10 +10108,12 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu 
*vcpu)
                ".global vmx_return \n\t"
                "vmx_return: " _ASM_PTR " 2b \n\t"
                ".popsection"
-             : : "c"(vmx), "d"((unsigned long)HOST_RSP), "S"(evmcs_rsp),
+             : : "c"(vmx), "d"((unsigned long)HOST_RSP), "S"(current_evmcs),
+               [enable_evmcs]"i"(&enable_evmcs),
                [launched]"i"(offsetof(struct vcpu_vmx, __launched)),
                [fail]"i"(offsetof(struct vcpu_vmx, fail)),
                [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)),
+               [evmcs_hrsp]"i"(offsetof(struct hv_enlightened_vmcs, host_rsp)),
                [rax]"i"(offsetof(struct vcpu_vmx, 
vcpu.arch.regs[VCPU_REGS_RAX])),
                [rbx]"i"(offsetof(struct vcpu_vmx, 
vcpu.arch.regs[VCPU_REGS_RBX])),
                [rcx]"i"(offsetof(struct vcpu_vmx, 
vcpu.arch.regs[VCPU_REGS_RCX])),

What I particularly dislike is that we now depend on jump labels
internals. Generalizing this hack doesn't seem practical as
non-HAVE_JUMP_LABEL path cloobbers FLAGS and requiring users to know
that is cumbersome...

I'd say 'too ugly' but I can continue investigating if there're fresh ideas.

-- 
  Vitaly

Reply via email to