diff mbox series

[1/2] KVM: x86: introduce definitions to support static calls for kvm_x86_ops

Message ID ce483ce4a1920a3c1c4e5deea11648d75f2a7b80.1610379877.git.jbaron@akamai.com (mailing list archive)
State New, archived
Headers show
Series Use static_call for kvm_x86_ops | expand

Commit Message

Jason Baron Jan. 11, 2021, 4:57 p.m. UTC
Use static calls to improve kvm_x86_ops performance. Introduce the
definitions that will be used by a subsequent patch to actualize the
savings.

Note that all kvm_x86_ops are covered here except for 'pmu_ops' and
'nested ops'. I think they can be covered by static calls in a simlilar
manner, but were omitted from this series to reduce scope and because
I don't think they have as large of a performance impact.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Jason Baron <jbaron@akamai.com>
---
 arch/x86/include/asm/kvm_host.h | 65 +++++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/x86.c              |  5 ++++
 2 files changed, 70 insertions(+)

Comments

Sean Christopherson Jan. 12, 2021, 11:04 p.m. UTC | #1
On Mon, Jan 11, 2021, Jason Baron wrote:
> Use static calls to improve kvm_x86_ops performance. Introduce the
> definitions that will be used by a subsequent patch to actualize the
> savings.
> 
> Note that all kvm_x86_ops are covered here except for 'pmu_ops' and
> 'nested ops'. I think they can be covered by static calls in a simlilar
> manner, but were omitted from this series to reduce scope and because
> I don't think they have as large of a performance impact.
> 
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Andrea Arcangeli <aarcange@redhat.com>
> Signed-off-by: Jason Baron <jbaron@akamai.com>
> ---
>  arch/x86/include/asm/kvm_host.h | 65 +++++++++++++++++++++++++++++++++++++++++
>  arch/x86/kvm/x86.c              |  5 ++++
>  2 files changed, 70 insertions(+)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 3ab7b46..e947522 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1087,6 +1087,65 @@ static inline u16 kvm_lapic_irq_dest_mode(bool dest_mode_logical)
>  	return dest_mode_logical ? APIC_DEST_LOGICAL : APIC_DEST_PHYSICAL;
>  }
>  
> +/*
> + * static calls cover all kvm_x86_ops except for functions under pmu_ops and
> + * nested_ops.
> + */
> +#define FOREACH_KVM_X86_OPS(F) \
> +	F(hardware_enable); F(hardware_disable); F(hardware_unsetup);	       \
> +	F(cpu_has_accelerated_tpr); F(has_emulated_msr);		       \
> +	F(vcpu_after_set_cpuid); F(vm_init); F(vm_destroy); F(vcpu_create);    \
> +	F(vcpu_free); F(vcpu_reset); F(prepare_guest_switch); F(vcpu_load);    \
> +	F(vcpu_put); F(update_exception_bitmap); F(get_msr); F(set_msr);       \
> +	F(get_segment_base); F(get_segment); F(get_cpl); F(set_segment);       \
> +	F(get_cs_db_l_bits); F(set_cr0); F(is_valid_cr4); F(set_cr4);	       \
> +	F(set_efer); F(get_idt); F(set_idt); F(get_gdt); F(set_gdt);	       \
> +	F(sync_dirty_debug_regs); F(set_dr7); F(cache_reg); F(get_rflags);     \
> +	F(set_rflags); F(tlb_flush_all); F(tlb_flush_current);		       \
> +	F(tlb_remote_flush); F(tlb_remote_flush_with_range); F(tlb_flush_gva); \
> +	F(tlb_flush_guest); F(run); F(handle_exit);			       \
> +	F(skip_emulated_instruction); F(update_emulated_instruction);	       \
> +	F(set_interrupt_shadow); F(get_interrupt_shadow); F(patch_hypercall);  \
> +	F(set_irq); F(set_nmi); F(queue_exception); F(cancel_injection);       \
> +	F(interrupt_allowed); F(nmi_allowed); F(get_nmi_mask); F(set_nmi_mask);\
> +	F(enable_nmi_window); F(enable_irq_window); F(update_cr8_intercept);   \
> +	F(check_apicv_inhibit_reasons); F(pre_update_apicv_exec_ctrl);	       \
> +	F(refresh_apicv_exec_ctrl); F(hwapic_irr_update); F(hwapic_isr_update);\
> +	F(guest_apic_has_interrupt); F(load_eoi_exitmap);		       \
> +	F(set_virtual_apic_mode); F(set_apic_access_page_addr);		       \
> +	F(deliver_posted_interrupt); F(sync_pir_to_irr); F(set_tss_addr);      \
> +	F(set_identity_map_addr); F(get_mt_mask); F(load_mmu_pgd);	       \
> +	F(has_wbinvd_exit); F(write_l1_tsc_offset); F(get_exit_info);	       \
> +	F(check_intercept); F(handle_exit_irqoff); F(request_immediate_exit);  \
> +	F(sched_in); F(slot_enable_log_dirty); F(slot_disable_log_dirty);      \
> +	F(flush_log_dirty); F(enable_log_dirty_pt_masked);		       \
> +	F(cpu_dirty_log_size); F(pre_block); F(post_block); F(vcpu_blocking);  \
> +	F(vcpu_unblocking); F(update_pi_irte); F(apicv_post_state_restore);    \
> +	F(dy_apicv_has_pending_interrupt); F(set_hv_timer); F(cancel_hv_timer);\
> +	F(setup_mce); F(smi_allowed); F(pre_enter_smm); F(pre_leave_smm);      \
> +	F(enable_smi_window); F(mem_enc_op); F(mem_enc_reg_region);	       \
> +	F(mem_enc_unreg_region); F(get_msr_feature);			       \
> +	F(can_emulate_instruction); F(apic_init_signal_blocked);	       \
> +	F(enable_direct_tlbflush); F(migrate_timers); F(msr_filter_changed);   \
> +	F(complete_emulated_msr)

What about adding a dedicated .h file for this beast?  Then it won't be so
painful to do one function per line.  As is, updates to kvm_x86_ops will be
messy.

And add yet another macro layer (or maybe just tweak this one?) so that the
caller controls the line ending?  I suppose you could also just use a comma, but
that's a bit dirty...

That would also allow using this to declare vmx_x86_ops and svm_x86_ops, which
would need a comma insteat of a semi-colon.  There have a been a few attempts to
add a bit of automation to {vmx,svm}_x86_ops, this seems like it would be good
motivation to go in a different direction and declare/define all ops, e.g. the
VMX/SVM code could simply do something like:

#define DECLARE_VMX_X86_OP(func) \
	.func = vmx_##func

static struct kvm_x86_ops vmx_x86_ops __initdata = {
	.vm_size = sizeof(struct kvm_vmx),
	.vm_init = vmx_vm_init,

	.pmu_ops = &intel_pmu_ops,
	.nested_ops = &vmx_nested_ops,

	FOREACH_KVM_X86_OPS(DECLARE_VMX_X86_OP)
};
Jason Baron Jan. 13, 2021, 4:12 a.m. UTC | #2
On 1/12/21 6:04 PM, Sean Christopherson wrote:
> On Mon, Jan 11, 2021, Jason Baron wrote:
>> Use static calls to improve kvm_x86_ops performance. Introduce the
>> definitions that will be used by a subsequent patch to actualize the
>> savings.
>>
>> Note that all kvm_x86_ops are covered here except for 'pmu_ops' and
>> 'nested ops'. I think they can be covered by static calls in a simlilar
>> manner, but were omitted from this series to reduce scope and because
>> I don't think they have as large of a performance impact.
>>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Cc: Ingo Molnar <mingo@redhat.com>
>> Cc: Borislav Petkov <bp@alien8.de>
>> Cc: Peter Zijlstra <peterz@infradead.org>
>> Cc: Andrea Arcangeli <aarcange@redhat.com>
>> Signed-off-by: Jason Baron <jbaron@akamai.com>
>> ---
>>   arch/x86/include/asm/kvm_host.h | 65 +++++++++++++++++++++++++++++++++++++++++
>>   arch/x86/kvm/x86.c              |  5 ++++
>>   2 files changed, 70 insertions(+)
>>
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index 3ab7b46..e947522 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1087,6 +1087,65 @@ static inline u16 kvm_lapic_irq_dest_mode(bool dest_mode_logical)
>>   	return dest_mode_logical ? APIC_DEST_LOGICAL : APIC_DEST_PHYSICAL;
>>   }
>>   
>> +/*
>> + * static calls cover all kvm_x86_ops except for functions under pmu_ops and
>> + * nested_ops.
>> + */
>> +#define FOREACH_KVM_X86_OPS(F) \
>> +	F(hardware_enable); F(hardware_disable); F(hardware_unsetup);	       \
>> +	F(cpu_has_accelerated_tpr); F(has_emulated_msr);		       \
>> +	F(vcpu_after_set_cpuid); F(vm_init); F(vm_destroy); F(vcpu_create);    \
>> +	F(vcpu_free); F(vcpu_reset); F(prepare_guest_switch); F(vcpu_load);    \
>> +	F(vcpu_put); F(update_exception_bitmap); F(get_msr); F(set_msr);       \
>> +	F(get_segment_base); F(get_segment); F(get_cpl); F(set_segment);       \
>> +	F(get_cs_db_l_bits); F(set_cr0); F(is_valid_cr4); F(set_cr4);	       \
>> +	F(set_efer); F(get_idt); F(set_idt); F(get_gdt); F(set_gdt);	       \
>> +	F(sync_dirty_debug_regs); F(set_dr7); F(cache_reg); F(get_rflags);     \
>> +	F(set_rflags); F(tlb_flush_all); F(tlb_flush_current);		       \
>> +	F(tlb_remote_flush); F(tlb_remote_flush_with_range); F(tlb_flush_gva); \
>> +	F(tlb_flush_guest); F(run); F(handle_exit);			       \
>> +	F(skip_emulated_instruction); F(update_emulated_instruction);	       \
>> +	F(set_interrupt_shadow); F(get_interrupt_shadow); F(patch_hypercall);  \
>> +	F(set_irq); F(set_nmi); F(queue_exception); F(cancel_injection);       \
>> +	F(interrupt_allowed); F(nmi_allowed); F(get_nmi_mask); F(set_nmi_mask);\
>> +	F(enable_nmi_window); F(enable_irq_window); F(update_cr8_intercept);   \
>> +	F(check_apicv_inhibit_reasons); F(pre_update_apicv_exec_ctrl);	       \
>> +	F(refresh_apicv_exec_ctrl); F(hwapic_irr_update); F(hwapic_isr_update);\
>> +	F(guest_apic_has_interrupt); F(load_eoi_exitmap);		       \
>> +	F(set_virtual_apic_mode); F(set_apic_access_page_addr);		       \
>> +	F(deliver_posted_interrupt); F(sync_pir_to_irr); F(set_tss_addr);      \
>> +	F(set_identity_map_addr); F(get_mt_mask); F(load_mmu_pgd);	       \
>> +	F(has_wbinvd_exit); F(write_l1_tsc_offset); F(get_exit_info);	       \
>> +	F(check_intercept); F(handle_exit_irqoff); F(request_immediate_exit);  \
>> +	F(sched_in); F(slot_enable_log_dirty); F(slot_disable_log_dirty);      \
>> +	F(flush_log_dirty); F(enable_log_dirty_pt_masked);		       \
>> +	F(cpu_dirty_log_size); F(pre_block); F(post_block); F(vcpu_blocking);  \
>> +	F(vcpu_unblocking); F(update_pi_irte); F(apicv_post_state_restore);    \
>> +	F(dy_apicv_has_pending_interrupt); F(set_hv_timer); F(cancel_hv_timer);\
>> +	F(setup_mce); F(smi_allowed); F(pre_enter_smm); F(pre_leave_smm);      \
>> +	F(enable_smi_window); F(mem_enc_op); F(mem_enc_reg_region);	       \
>> +	F(mem_enc_unreg_region); F(get_msr_feature);			       \
>> +	F(can_emulate_instruction); F(apic_init_signal_blocked);	       \
>> +	F(enable_direct_tlbflush); F(migrate_timers); F(msr_filter_changed);   \
>> +	F(complete_emulated_msr)
> What about adding a dedicated .h file for this beast?  Then it won't be so
> painful to do one function per line.  As is, updates to kvm_x86_ops will be
> messy.
Hi,

I'm fine moving it to a new header. I had put it right above
'struct kvm_x86_ops' in arch/x86/include/asm/kvm_host.h, such
that it would be updated along with kvm_x86_ops changes. But
I can put a big comment there to update the new header.

>
> And add yet another macro layer (or maybe just tweak this one?) so that the
> caller controls the line ending?  I suppose you could also just use a comma, but
> that's a bit dirty...
>
> That would also allow using this to declare vmx_x86_ops and svm_x86_ops, which
> would need a comma insteat of a semi-colon.  There have a been a few attempts to
> add a bit of automation to {vmx,svm}_x86_ops, this seems like it would be good
> motivation to go in a different direction and declare/define all ops, e.g. the
> VMX/SVM code could simply do something like:
>
> #define DECLARE_VMX_X86_OP(func) \
> 	.func = vmx_##func
>
> static struct kvm_x86_ops vmx_x86_ops __initdata = {
> 	.vm_size = sizeof(struct kvm_vmx),
> 	.vm_init = vmx_vm_init,
>
> 	.pmu_ops = &intel_pmu_ops,
> 	.nested_ops = &vmx_nested_ops,
>
> 	FOREACH_KVM_X86_OPS(DECLARE_VMX_X86_OP)
> };
>
Looking at the vmx definitions I see quite a few that don't
match that naming. For example:

hardware_unsetup,
hardware_enable,
hardware_disable,
report_flexpriority,
update_exception_bitmap,
enable_nmi_window,
enable_irq_window,
update_cr8_intercept,
pi_has_pending_interrupt,
cpu_has_vmx_wbinvd_exit,
pi_update_irte,
kvm_complete_insn_gp,

So I'm not sure if we want to extend these macros to
vmx/svm.

Thanks,

-Jason
Paolo Bonzini Jan. 13, 2021, 12:47 p.m. UTC | #3
On 13/01/21 05:12, Jason Baron wrote:
>>
> Looking at the vmx definitions I see quite a few that don't
> match that naming. For example:
> 
> hardware_unsetup,
> hardware_enable,
> hardware_disable,
> report_flexpriority,
> update_exception_bitmap,
> enable_nmi_window,
> enable_irq_window,
> update_cr8_intercept,
> pi_has_pending_interrupt,
> cpu_has_vmx_wbinvd_exit,
> pi_update_irte,
> kvm_complete_insn_gp,
> 
> So I'm not sure if we want to extend these macros to
> vmx/svm.

Don't do it yourself, but once you introduce the new header it becomes a 
no-brainer to switch the declarations to use it.  So let's plan the new 
header to make that switch easy.

Using trailing commas unconditionally would be okay, i.e.

#define X86_OP(func)     .func = vmx_##func,
#include "kvm-x86-ops.h"

and leave out the terminator/delimiter in kvm-x86-ops.h.  This is 
similar to how we use vmx/vmcs_shadow_fields.h:

#define SHADOW_FIELD_RO(x, y) { x, offsetof(struct vmcs12, y) },
#include "vmcs_shadow_fields.h"

#define SHADOW_FIELD_RW(x, y) case x:
#include "vmcs_shadow_fields.h"

Thanks,

Paolo
Paolo Bonzini Jan. 13, 2021, 12:53 p.m. UTC | #4
On 11/01/21 17:57, Jason Baron wrote:
> +#define DEFINE_KVM_OPS_STATIC_CALL(func)	\
> +	DEFINE_STATIC_CALL_NULL(kvm_x86_##func,	\
> +				*(((struct kvm_x86_ops *)0)->func))
> +#define DEFINE_KVM_OPS_STATIC_CALLS() \
> +	FOREACH_KVM_X86_OPS(DEFINE_KVM_OPS_STATIC_CALL)

Something wrong here?

> +#define DECLARE_KVM_OPS_STATIC_CALL(func)	\
> +	DECLARE_STATIC_CALL(kvm_x86_##func,	\
> +			    *(((struct kvm_x86_ops *)0)->func))
> +#define DECLARE_KVM_OPS_STATIC_CALLS()		\
> +	FOREACH_KVM_X86_OPS(DECLARE_KVM_OPS_STATIC_CALL)
> +
> +#define KVM_OPS_STATIC_CALL_UPDATE(func)	\
> +	static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> +#define KVM_OPS_STATIC_CALL_UPDATES()		\
> +	FOREACH_KVM_X86_OPS(KVM_OPS_STATIC_CALL_UPDATE)
> +
>   struct kvm_x86_ops {
>   	int (*hardware_enable)(void);
>   	void (*hardware_disable)(void);
> @@ -1326,6 +1385,12 @@ extern u64 __read_mostly host_efer;
>   extern bool __read_mostly allow_smaller_maxphyaddr;
>   extern struct kvm_x86_ops kvm_x86_ops;
>   
> +DECLARE_KVM_OPS_STATIC_CALLS();
> +static inline void kvm_ops_static_call_update(void)
> +{
> +	KVM_OPS_STATIC_CALL_UPDATES();
> +}

This would become

#define KVM_X86_OP(func) \
	DECLARE_STATIC_CALL(kvm_x86_##func,	\
			    *(((struct kvm_x86_ops *)0)->func));

#include <asm/kvm-x86-ops.h>

static inline void kvm_ops_static_call_update(void)
{
#define KVM_X86_OP(func) \
   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
#include <asm/kvm-x86-ops.h>
}

If you need to choose between DECLARE_STATIC_CALL_NULL and 
DECLARE_STATIC_CALL, you can have kvm-x86-ops.h use one of two macros 
KVM_X86_OP_NULL and KVM_X86_OP.

#define KVM_X86_OP(func) \
	DECLARE_STATIC_CALL(kvm_x86_##func,	\
			    *(((struct kvm_x86_ops *)0)->func));

#define KVM_X86_OP_NULL(func) \
	DECLARE_STATIC_CALL_NULL(kvm_x86_##func,	\
			    *(((struct kvm_x86_ops *)0)->func));

#include <asm/kvm-x86-ops.h>

...

#define KVM_X86_OP(func) \
   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
#define KVM_X86_OP_NULL(func) \
   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
#include <asm/kvm-x86-ops.h>

In that case vmx.c and svm.c could define KVM_X86_OP_NULL to an empty 
string and list the optional callbacks manually.

Paolo
Jason Baron Jan. 13, 2021, 4:16 p.m. UTC | #5
On 1/13/21 7:53 AM, Paolo Bonzini wrote:
> On 11/01/21 17:57, Jason Baron wrote:
>> +#define DEFINE_KVM_OPS_STATIC_CALL(func)    \
>> +    DEFINE_STATIC_CALL_NULL(kvm_x86_##func,    \
>> +                *(((struct kvm_x86_ops *)0)->func))
>> +#define DEFINE_KVM_OPS_STATIC_CALLS() \
>> +    FOREACH_KVM_X86_OPS(DEFINE_KVM_OPS_STATIC_CALL)
> 
> Something wrong here?

Hmmm...not sure what you are getting at here.

> 
>> +#define DECLARE_KVM_OPS_STATIC_CALL(func)    \
>> +    DECLARE_STATIC_CALL(kvm_x86_##func,    \
>> +                *(((struct kvm_x86_ops *)0)->func))
>> +#define DECLARE_KVM_OPS_STATIC_CALLS()        \
>> +    FOREACH_KVM_X86_OPS(DECLARE_KVM_OPS_STATIC_CALL)
>> +
>> +#define KVM_OPS_STATIC_CALL_UPDATE(func)    \
>> +    static_call_update(kvm_x86_##func, kvm_x86_ops.func)
>> +#define KVM_OPS_STATIC_CALL_UPDATES()        \
>> +    FOREACH_KVM_X86_OPS(KVM_OPS_STATIC_CALL_UPDATE)
>> +
>>   struct kvm_x86_ops {
>>       int (*hardware_enable)(void);
>>       void (*hardware_disable)(void);
>> @@ -1326,6 +1385,12 @@ extern u64 __read_mostly host_efer;
>>   extern bool __read_mostly allow_smaller_maxphyaddr;
>>   extern struct kvm_x86_ops kvm_x86_ops;
>>   +DECLARE_KVM_OPS_STATIC_CALLS();
>> +static inline void kvm_ops_static_call_update(void)
>> +{
>> +    KVM_OPS_STATIC_CALL_UPDATES();
>> +}
> 
> This would become
> 
> #define KVM_X86_OP(func) \
>     DECLARE_STATIC_CALL(kvm_x86_##func,    \
>                 *(((struct kvm_x86_ops *)0)->func));
> 
> #include <asm/kvm-x86-ops.h>
> 
> static inline void kvm_ops_static_call_update(void)
> {
> #define KVM_X86_OP(func) \
>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> #include <asm/kvm-x86-ops.h>
> }
> 
> If you need to choose between DECLARE_STATIC_CALL_NULL and DECLARE_STATIC_CALL, you can have kvm-x86-ops.h use one of two macros KVM_X86_OP_NULL and
> KVM_X86_OP.
> 
> #define KVM_X86_OP(func) \
>     DECLARE_STATIC_CALL(kvm_x86_##func,    \
>                 *(((struct kvm_x86_ops *)0)->func));
> 
> #define KVM_X86_OP_NULL(func) \
>     DECLARE_STATIC_CALL_NULL(kvm_x86_##func,    \
>                 *(((struct kvm_x86_ops *)0)->func));
> 
> #include <asm/kvm-x86-ops.h>
> 
> ...
> 
> #define KVM_X86_OP(func) \
>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> #define KVM_X86_OP_NULL(func) \
>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> #include <asm/kvm-x86-ops.h>
> 
> In that case vmx.c and svm.c could define KVM_X86_OP_NULL to an empty string and list the optional callbacks manually.
> 

Ok, yes, this all makes sense. So I looked at vmx/svm definitions
and I see that there are 5 definitions that are common that
don't use the vmx or svm prefix:

.update_exception_bitmap = update_exception_bitmap,
.enable_nmi_window = enable_nmi_window,
.enable_irq_window = enable_irq_window,
.update_cr8_intercept = update_cr8_intercept,
.enable_smi_window = enable_smi_window,

8 are specific to vmx that don't use the vmx prefix:

.hardware_unsetup = hardware_unsetup,
.hardware_enable = hardware_enable,
.hardware_disable = hardware_disable,
.cpu_has_accelerated_tpr = report_flexpriority,
.dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
.update_pi_irte = pi_update_irte,
.complete_emulated_msr = kvm_complete_insn_gp,

and finally 7 specific to svm that don't use the svm prefix:

.get_cs_db_l_bits = kvm_get_cs_db_l_bits,
.handle_exit = handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
.update_emulated_instruction = NULL,
.sync_pir_to_irr = kvm_lapic_find_highest_irr,
.apicv_post_state_restore = avic_post_state_restore,
.request_immediate_exit = __kvm_request_immediate_exit,


So we could set all of these to empty definitions and specifically
add the callbacks manually as you suggested. Or we could have 4
categories of macros:

1) KVM_X86_OP()  - for the usual case where we have the 'svm' or
'vmx' prefix.

2) KVM_X86_OP_NULL() - for the case where both svm and vmx want
to over-ride.

For the remaining cases I was thinking of having the VMX code
and svm code, add a define for 'VMX' or 'SVM' respectively and
then we could mark the vmx specific ones by adding something like
this to asm/kvm-x86-ops.h:

#ifndef VMX
 #define KVM_X86_OP_UNLESS_VMX(func) \
	KVM_X86_OP(func)
#else
 #define KVM_X86_OP_UNLESS_VMX(func)
#endif

and similarly for the svm specific ones:

#ifndef SVM
 #define KVM_X86_OP_UNLESS_SVM(func) \
	KVM_X86_OP(func)
#else
 #define KVM_X86_OP_UNLESS_SVM(func)
#endif


So in vmx.c you would have:

#define X86_OP(func)     .func = vmx_##func,
#define VMX 1
#include "kvm-x86-ops.h"

Or we could just use the KVM_X86_OP_NULL() macro for anything
that doesn't have a 'svm' or 'vmx' prefix as I think you were
suggesting? In that case I think there would then be 13 manual
additions for vmx and 12 for svm.

Thanks,

-Jason
Sean Christopherson Jan. 13, 2021, 4:29 p.m. UTC | #6
On Wed, Jan 13, 2021, Paolo Bonzini wrote:
> On 13/01/21 05:12, Jason Baron wrote:
> > > 
> > Looking at the vmx definitions I see quite a few that don't
> > match that naming. For example:
> > 
> > hardware_unsetup,
> > hardware_enable,
> > hardware_disable,
> > report_flexpriority,
> > update_exception_bitmap,
> > enable_nmi_window,
> > enable_irq_window,
> > update_cr8_intercept,
> > pi_has_pending_interrupt,
> > cpu_has_vmx_wbinvd_exit,
> > pi_update_irte,
> > kvm_complete_insn_gp,
> > 
> > So I'm not sure if we want to extend these macros to
> > vmx/svm.
> 
> Don't do it yourself, but once you introduce the new header it becomes a
> no-brainer to switch the declarations to use it.  So let's plan the new
> header to make that switch easy.

Ya, sorry if I didn't make it clear that the vmx/svm conversion is firmly out
of scope for this series.
Jason Baron Jan. 13, 2021, 4:30 p.m. UTC | #7
On 1/13/21 11:16 AM, Jason Baron wrote:
> 
> 
> On 1/13/21 7:53 AM, Paolo Bonzini wrote:
>> On 11/01/21 17:57, Jason Baron wrote:
>>> +#define DEFINE_KVM_OPS_STATIC_CALL(func)    \
>>> +    DEFINE_STATIC_CALL_NULL(kvm_x86_##func,    \
>>> +                *(((struct kvm_x86_ops *)0)->func))
>>> +#define DEFINE_KVM_OPS_STATIC_CALLS() \
>>> +    FOREACH_KVM_X86_OPS(DEFINE_KVM_OPS_STATIC_CALL)
>>
>> Something wrong here?
> 
> Hmmm...not sure what you are getting at here.
> 
>>
>>> +#define DECLARE_KVM_OPS_STATIC_CALL(func)    \
>>> +    DECLARE_STATIC_CALL(kvm_x86_##func,    \
>>> +                *(((struct kvm_x86_ops *)0)->func))
>>> +#define DECLARE_KVM_OPS_STATIC_CALLS()        \
>>> +    FOREACH_KVM_X86_OPS(DECLARE_KVM_OPS_STATIC_CALL)
>>> +
>>> +#define KVM_OPS_STATIC_CALL_UPDATE(func)    \
>>> +    static_call_update(kvm_x86_##func, kvm_x86_ops.func)
>>> +#define KVM_OPS_STATIC_CALL_UPDATES()        \
>>> +    FOREACH_KVM_X86_OPS(KVM_OPS_STATIC_CALL_UPDATE)
>>> +
>>>   struct kvm_x86_ops {
>>>       int (*hardware_enable)(void);
>>>       void (*hardware_disable)(void);
>>> @@ -1326,6 +1385,12 @@ extern u64 __read_mostly host_efer;
>>>   extern bool __read_mostly allow_smaller_maxphyaddr;
>>>   extern struct kvm_x86_ops kvm_x86_ops;
>>>   +DECLARE_KVM_OPS_STATIC_CALLS();
>>> +static inline void kvm_ops_static_call_update(void)
>>> +{
>>> +    KVM_OPS_STATIC_CALL_UPDATES();
>>> +}
>>
>> This would become
>>
>> #define KVM_X86_OP(func) \
>>     DECLARE_STATIC_CALL(kvm_x86_##func,    \
>>                 *(((struct kvm_x86_ops *)0)->func));
>>
>> #include <asm/kvm-x86-ops.h>
>>
>> static inline void kvm_ops_static_call_update(void)
>> {
>> #define KVM_X86_OP(func) \
>>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
>> #include <asm/kvm-x86-ops.h>
>> }
>>
>> If you need to choose between DECLARE_STATIC_CALL_NULL and DECLARE_STATIC_CALL, you can have kvm-x86-ops.h use one of two macros KVM_X86_OP_NULL and
>> KVM_X86_OP.
>>
>> #define KVM_X86_OP(func) \
>>     DECLARE_STATIC_CALL(kvm_x86_##func,    \
>>                 *(((struct kvm_x86_ops *)0)->func));
>>
>> #define KVM_X86_OP_NULL(func) \
>>     DECLARE_STATIC_CALL_NULL(kvm_x86_##func,    \
>>                 *(((struct kvm_x86_ops *)0)->func));
>>
>> #include <asm/kvm-x86-ops.h>
>>
>> ...
>>
>> #define KVM_X86_OP(func) \
>>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
>> #define KVM_X86_OP_NULL(func) \
>>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
>> #include <asm/kvm-x86-ops.h>
>>
>> In that case vmx.c and svm.c could define KVM_X86_OP_NULL to an empty string and list the optional callbacks manually.
>>
> 
> Ok, yes, this all makes sense. So I looked at vmx/svm definitions
> and I see that there are 5 definitions that are common that
> don't use the vmx or svm prefix:
> 
> .update_exception_bitmap = update_exception_bitmap,
> .enable_nmi_window = enable_nmi_window,
> .enable_irq_window = enable_irq_window,
> .update_cr8_intercept = update_cr8_intercept,
> .enable_smi_window = enable_smi_window,
> 
> 8 are specific to vmx that don't use the vmx prefix:
> 
> .hardware_unsetup = hardware_unsetup,
> .hardware_enable = hardware_enable,
> .hardware_disable = hardware_disable,
> .cpu_has_accelerated_tpr = report_flexpriority,
> .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
> .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
> .update_pi_irte = pi_update_irte,
> .complete_emulated_msr = kvm_complete_insn_gp,
> 
> and finally 7 specific to svm that don't use the svm prefix:
> 
> .get_cs_db_l_bits = kvm_get_cs_db_l_bits,
> .handle_exit = handle_exit,
> .skip_emulated_instruction = skip_emulated_instruction,
> .update_emulated_instruction = NULL,
> .sync_pir_to_irr = kvm_lapic_find_highest_irr,
> .apicv_post_state_restore = avic_post_state_restore,
> .request_immediate_exit = __kvm_request_immediate_exit,
> 
> 
> So we could set all of these to empty definitions and specifically
> add the callbacks manually as you suggested. Or we could have 4
> categories of macros:
> 
> 1) KVM_X86_OP()  - for the usual case where we have the 'svm' or
> 'vmx' prefix.
> 
> 2) KVM_X86_OP_NULL() - for the case where both svm and vmx want
> to over-ride.
> 
> For the remaining cases I was thinking of having the VMX code
> and svm code, add a define for 'VMX' or 'SVM' respectively and
> then we could mark the vmx specific ones by adding something like
> this to asm/kvm-x86-ops.h:
> 
> #ifndef VMX
>  #define KVM_X86_OP_UNLESS_VMX(func) \
> 	KVM_X86_OP(func)
> #else
>  #define KVM_X86_OP_UNLESS_VMX(func)
> #endif
> 
> and similarly for the svm specific ones:
> 
> #ifndef SVM
>  #define KVM_X86_OP_UNLESS_SVM(func) \
> 	KVM_X86_OP(func)
> #else
>  #define KVM_X86_OP_UNLESS_SVM(func)
> #endif
> 
> 
> So in vmx.c you would have:
> 
> #define X86_OP(func)     .func = vmx_##func,
> #define VMX 1
> #include "kvm-x86-ops.h"
> 
> Or we could just use the KVM_X86_OP_NULL() macro for anything
> that doesn't have a 'svm' or 'vmx' prefix as I think you were
> suggesting? In that case I think there would then be 13 manual
> additions for vmx and 12 for svm.
> 

Sorry this last bit is wrong. Using the KVM_X86_OP_NULL() for
all definitions that don't use 'svm' and 'vmx', would mean
manually defining all 20 in vmx and svm. Whereas if we we
mark some of them specific to vmx or svm, we can get away
with less - 13 manual for vmx and 12 manual for svm.

Thanks,

-Jason
Paolo Bonzini Jan. 13, 2021, 5:02 p.m. UTC | #8
On 13/01/21 17:16, Jason Baron wrote:
>>> +#define DEFINE_KVM_OPS_STATIC_CALL(func)    \
>>> +    DEFINE_STATIC_CALL_NULL(kvm_x86_##func,    \
>>> +                *(((struct kvm_x86_ops *)0)->func))
>>> +#define DEFINE_KVM_OPS_STATIC_CALLS() \
>>> +    FOREACH_KVM_X86_OPS(DEFINE_KVM_OPS_STATIC_CALL)
>> Something wrong here?
> Hmmm...not sure what you are getting at here.

I just misread define vs. declare.

> Or we could just use the KVM_X86_OP_NULL() macro for anything
> that doesn't have a 'svm' or 'vmx' prefix as I think you were
> suggesting?
>
> Using the KVM_X86_OP_NULL() for
> all definitions that don't use 'svm' and 'vmx', would mean
> manually defining all 20 in vmx and svm

Yes, that's the simplest thing to do.  Then we clean them up as we 
rename the functions.  If you want, go ahead and rename the five easy 
ones yourself.

Paolo

> .update_exception_bitmap = update_exception_bitmap,
> .enable_nmi_window = enable_nmi_window,
> .enable_irq_window = enable_irq_window,
> .update_cr8_intercept = update_cr8_intercept,
> .enable_smi_window = enable_smi_window,
Sean Christopherson Jan. 13, 2021, 5:11 p.m. UTC | #9
On Wed, Jan 13, 2021, Jason Baron wrote:
> 
> On 1/13/21 7:53 AM, Paolo Bonzini wrote:
> > #define KVM_X86_OP(func) \
> >   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> > #define KVM_X86_OP_NULL(func) \
> >   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> > #include <asm/kvm-x86-ops.h>
> > 
> > In that case vmx.c and svm.c could define KVM_X86_OP_NULL to an empty
> > string and list the optional callbacks manually.
> > 
> 
> Ok, yes, this all makes sense. So I looked at vmx/svm definitions
> and I see that there are 5 definitions that are common that
> don't use the vmx or svm prefix:

We'll rename the helpers when doing the conversion, i.e. you can safely assume
that all VMX/SVM functions will use the pattern {vmx,svm}_##func.  I did all the
renaming a few months back, but it got tossed away when svm.c was broken up.

> .update_exception_bitmap = update_exception_bitmap,
> .enable_nmi_window = enable_nmi_window,
> .enable_irq_window = enable_irq_window,
> .update_cr8_intercept = update_cr8_intercept,
> .enable_smi_window = enable_smi_window,
Sean Christopherson Jan. 13, 2021, 5:17 p.m. UTC | #10
On Wed, Jan 13, 2021, Paolo Bonzini wrote:
> If you need to choose between DECLARE_STATIC_CALL_NULL and
> DECLARE_STATIC_CALL, you can have kvm-x86-ops.h use one of two macros
> KVM_X86_OP_NULL and KVM_X86_OP.
> 
> #define KVM_X86_OP(func) \
> 	DECLARE_STATIC_CALL(kvm_x86_##func,	\
> 			    *(((struct kvm_x86_ops *)0)->func));
> 
> #define KVM_X86_OP_NULL(func) \
> 	DECLARE_STATIC_CALL_NULL(kvm_x86_##func,	\

Gah, DECLARE_STATIC_CALL_NULL doesn't exist, though it's referenced in a comment.
I assume these should be s/DECLARE/DEFINE?  I haven't fully grokked the static
call code yet...

> 			    *(((struct kvm_x86_ops *)0)->func));
> 
> #include <asm/kvm-x86-ops.h>
> 
> ...
> 
> #define KVM_X86_OP(func) \
>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> #define KVM_X86_OP_NULL(func) \
>   static_call_update(kvm_x86_##func, kvm_x86_ops.func)
> #include <asm/kvm-x86-ops.h>
> 
> In that case vmx.c and svm.c could define KVM_X86_OP_NULL to an empty string
> and list the optional callbacks manually.
> 
> Paolo
>
diff mbox series

Patch

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3ab7b46..e947522 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1087,6 +1087,65 @@  static inline u16 kvm_lapic_irq_dest_mode(bool dest_mode_logical)
 	return dest_mode_logical ? APIC_DEST_LOGICAL : APIC_DEST_PHYSICAL;
 }
 
+/*
+ * static calls cover all kvm_x86_ops except for functions under pmu_ops and
+ * nested_ops.
+ */
+#define FOREACH_KVM_X86_OPS(F) \
+	F(hardware_enable); F(hardware_disable); F(hardware_unsetup);	       \
+	F(cpu_has_accelerated_tpr); F(has_emulated_msr);		       \
+	F(vcpu_after_set_cpuid); F(vm_init); F(vm_destroy); F(vcpu_create);    \
+	F(vcpu_free); F(vcpu_reset); F(prepare_guest_switch); F(vcpu_load);    \
+	F(vcpu_put); F(update_exception_bitmap); F(get_msr); F(set_msr);       \
+	F(get_segment_base); F(get_segment); F(get_cpl); F(set_segment);       \
+	F(get_cs_db_l_bits); F(set_cr0); F(is_valid_cr4); F(set_cr4);	       \
+	F(set_efer); F(get_idt); F(set_idt); F(get_gdt); F(set_gdt);	       \
+	F(sync_dirty_debug_regs); F(set_dr7); F(cache_reg); F(get_rflags);     \
+	F(set_rflags); F(tlb_flush_all); F(tlb_flush_current);		       \
+	F(tlb_remote_flush); F(tlb_remote_flush_with_range); F(tlb_flush_gva); \
+	F(tlb_flush_guest); F(run); F(handle_exit);			       \
+	F(skip_emulated_instruction); F(update_emulated_instruction);	       \
+	F(set_interrupt_shadow); F(get_interrupt_shadow); F(patch_hypercall);  \
+	F(set_irq); F(set_nmi); F(queue_exception); F(cancel_injection);       \
+	F(interrupt_allowed); F(nmi_allowed); F(get_nmi_mask); F(set_nmi_mask);\
+	F(enable_nmi_window); F(enable_irq_window); F(update_cr8_intercept);   \
+	F(check_apicv_inhibit_reasons); F(pre_update_apicv_exec_ctrl);	       \
+	F(refresh_apicv_exec_ctrl); F(hwapic_irr_update); F(hwapic_isr_update);\
+	F(guest_apic_has_interrupt); F(load_eoi_exitmap);		       \
+	F(set_virtual_apic_mode); F(set_apic_access_page_addr);		       \
+	F(deliver_posted_interrupt); F(sync_pir_to_irr); F(set_tss_addr);      \
+	F(set_identity_map_addr); F(get_mt_mask); F(load_mmu_pgd);	       \
+	F(has_wbinvd_exit); F(write_l1_tsc_offset); F(get_exit_info);	       \
+	F(check_intercept); F(handle_exit_irqoff); F(request_immediate_exit);  \
+	F(sched_in); F(slot_enable_log_dirty); F(slot_disable_log_dirty);      \
+	F(flush_log_dirty); F(enable_log_dirty_pt_masked);		       \
+	F(cpu_dirty_log_size); F(pre_block); F(post_block); F(vcpu_blocking);  \
+	F(vcpu_unblocking); F(update_pi_irte); F(apicv_post_state_restore);    \
+	F(dy_apicv_has_pending_interrupt); F(set_hv_timer); F(cancel_hv_timer);\
+	F(setup_mce); F(smi_allowed); F(pre_enter_smm); F(pre_leave_smm);      \
+	F(enable_smi_window); F(mem_enc_op); F(mem_enc_reg_region);	       \
+	F(mem_enc_unreg_region); F(get_msr_feature);			       \
+	F(can_emulate_instruction); F(apic_init_signal_blocked);	       \
+	F(enable_direct_tlbflush); F(migrate_timers); F(msr_filter_changed);   \
+	F(complete_emulated_msr)
+
+#define DEFINE_KVM_OPS_STATIC_CALL(func)	\
+	DEFINE_STATIC_CALL_NULL(kvm_x86_##func,	\
+				*(((struct kvm_x86_ops *)0)->func))
+#define DEFINE_KVM_OPS_STATIC_CALLS() \
+	FOREACH_KVM_X86_OPS(DEFINE_KVM_OPS_STATIC_CALL)
+
+#define DECLARE_KVM_OPS_STATIC_CALL(func)	\
+	DECLARE_STATIC_CALL(kvm_x86_##func,	\
+			    *(((struct kvm_x86_ops *)0)->func))
+#define DECLARE_KVM_OPS_STATIC_CALLS()		\
+	FOREACH_KVM_X86_OPS(DECLARE_KVM_OPS_STATIC_CALL)
+
+#define KVM_OPS_STATIC_CALL_UPDATE(func)	\
+	static_call_update(kvm_x86_##func, kvm_x86_ops.func)
+#define KVM_OPS_STATIC_CALL_UPDATES()		\
+	FOREACH_KVM_X86_OPS(KVM_OPS_STATIC_CALL_UPDATE)
+
 struct kvm_x86_ops {
 	int (*hardware_enable)(void);
 	void (*hardware_disable)(void);
@@ -1326,6 +1385,12 @@  extern u64 __read_mostly host_efer;
 extern bool __read_mostly allow_smaller_maxphyaddr;
 extern struct kvm_x86_ops kvm_x86_ops;
 
+DECLARE_KVM_OPS_STATIC_CALLS();
+static inline void kvm_ops_static_call_update(void)
+{
+	KVM_OPS_STATIC_CALL_UPDATES();
+}
+
 #define __KVM_HAVE_ARCH_VM_ALLOC
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3f7c1fc..6ae32ab 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -113,6 +113,11 @@  static int sync_regs(struct kvm_vcpu *vcpu);
 struct kvm_x86_ops kvm_x86_ops __read_mostly;
 EXPORT_SYMBOL_GPL(kvm_x86_ops);
 
+DEFINE_KVM_OPS_STATIC_CALLS();
+EXPORT_STATIC_CALL_GPL(kvm_x86_get_cs_db_l_bits);
+EXPORT_STATIC_CALL_GPL(kvm_x86_cache_reg);
+EXPORT_STATIC_CALL_GPL(kvm_x86_tlb_flush_current);
+
 static bool __read_mostly ignore_msrs = 0;
 module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR);