x86/hyper-v: allocate and use Virtual Processor Assist Pages

Virtual Processor Assist Pages usage allows us to do optimized EOI
processing for APIC, enable Enlightened VMCS support in KVM and more.
struct hv_vp_assist_page is defined according to the Hyper-V TLFS v5.0b.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
This commit is contained in:
Vitaly Kuznetsov 2018-03-20 15:02:08 +01:00 committed by Radim Krčmář
parent d4abc577bb
commit a46d15cc1a
3 changed files with 66 additions and 3 deletions

View File

@ -88,11 +88,15 @@ EXPORT_SYMBOL_GPL(hyperv_cs);
u32 *hv_vp_index; u32 *hv_vp_index;
EXPORT_SYMBOL_GPL(hv_vp_index); EXPORT_SYMBOL_GPL(hv_vp_index);
struct hv_vp_assist_page **hv_vp_assist_page;
EXPORT_SYMBOL_GPL(hv_vp_assist_page);
u32 hv_max_vp_index; u32 hv_max_vp_index;
static int hv_cpu_init(unsigned int cpu) static int hv_cpu_init(unsigned int cpu)
{ {
u64 msr_vp_index; u64 msr_vp_index;
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
hv_get_vp_index(msr_vp_index); hv_get_vp_index(msr_vp_index);
@ -101,6 +105,22 @@ static int hv_cpu_init(unsigned int cpu)
if (msr_vp_index > hv_max_vp_index) if (msr_vp_index > hv_max_vp_index)
hv_max_vp_index = msr_vp_index; hv_max_vp_index = msr_vp_index;
if (!hv_vp_assist_page)
return 0;
if (!*hvp)
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (*hvp) {
u64 val;
val = vmalloc_to_pfn(*hvp);
val = (val << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT) |
HV_X64_MSR_VP_ASSIST_PAGE_ENABLE;
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, val);
}
return 0; return 0;
} }
@ -198,6 +218,9 @@ static int hv_cpu_die(unsigned int cpu)
struct hv_reenlightenment_control re_ctrl; struct hv_reenlightenment_control re_ctrl;
unsigned int new_cpu; unsigned int new_cpu;
if (hv_vp_assist_page && hv_vp_assist_page[cpu])
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, 0);
if (hv_reenlightenment_cb == NULL) if (hv_reenlightenment_cb == NULL)
return 0; return 0;
@ -224,6 +247,7 @@ void hyperv_init(void)
{ {
u64 guest_id, required_msrs; u64 guest_id, required_msrs;
union hv_x64_msr_hypercall_contents hypercall_msr; union hv_x64_msr_hypercall_contents hypercall_msr;
int cpuhp;
if (x86_hyper_type != X86_HYPER_MS_HYPERV) if (x86_hyper_type != X86_HYPER_MS_HYPERV)
return; return;
@ -241,9 +265,17 @@ void hyperv_init(void)
if (!hv_vp_index) if (!hv_vp_index)
return; return;
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online", hv_vp_assist_page = kcalloc(num_possible_cpus(),
hv_cpu_init, hv_cpu_die) < 0) sizeof(*hv_vp_assist_page), GFP_KERNEL);
if (!hv_vp_assist_page) {
ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED;
goto free_vp_index; goto free_vp_index;
}
cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
hv_cpu_init, hv_cpu_die);
if (cpuhp < 0)
goto free_vp_assist_page;
/* /*
* Setup the hypercall page and enable hypercalls. * Setup the hypercall page and enable hypercalls.
@ -256,7 +288,7 @@ void hyperv_init(void)
hv_hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX); hv_hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
if (hv_hypercall_pg == NULL) { if (hv_hypercall_pg == NULL) {
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
goto free_vp_index; goto remove_cpuhp_state;
} }
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@ -304,6 +336,11 @@ register_msr_cs:
return; return;
remove_cpuhp_state:
cpuhp_remove_state(cpuhp);
free_vp_assist_page:
kfree(hv_vp_assist_page);
hv_vp_assist_page = NULL;
free_vp_index: free_vp_index:
kfree(hv_vp_index); kfree(hv_vp_index);
hv_vp_index = NULL; hv_vp_index = NULL;

View File

@ -163,6 +163,9 @@
/* Recommend using the newer ExProcessorMasks interface */ /* Recommend using the newer ExProcessorMasks interface */
#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11) #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
/* Recommend using enlightened VMCS */
#define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED (1 << 14)
/* /*
* Crash notification flag. * Crash notification flag.
*/ */
@ -480,6 +483,16 @@ struct hv_timer_message_payload {
__u64 delivery_time; /* When the message was delivered */ __u64 delivery_time; /* When the message was delivered */
}; };
/* Define virtual processor assist page structure. */
struct hv_vp_assist_page {
__u32 apic_assist;
__u32 reserved;
__u64 vtl_control[2];
__u64 nested_enlightenments_control[2];
__u32 enlighten_vmentry;
__u64 current_nested_vmcs;
};
#define HV_STIMER_ENABLE (1ULL << 0) #define HV_STIMER_ENABLE (1ULL << 0)
#define HV_STIMER_PERIODIC (1ULL << 1) #define HV_STIMER_PERIODIC (1ULL << 1)
#define HV_STIMER_LAZY (1ULL << 2) #define HV_STIMER_LAZY (1ULL << 2)

View File

@ -218,6 +218,15 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
*/ */
extern u32 *hv_vp_index; extern u32 *hv_vp_index;
extern u32 hv_max_vp_index; extern u32 hv_max_vp_index;
extern struct hv_vp_assist_page **hv_vp_assist_page;
static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
{
if (!hv_vp_assist_page)
return NULL;
return hv_vp_assist_page[cpu];
}
/** /**
* hv_cpu_number_to_vp_number() - Map CPU to VP. * hv_cpu_number_to_vp_number() - Map CPU to VP.
@ -254,6 +263,10 @@ static inline void hyperv_setup_mmu_ops(void) {}
static inline void set_hv_tscchange_cb(void (*cb)(void)) {} static inline void set_hv_tscchange_cb(void (*cb)(void)) {}
static inline void clear_hv_tscchange_cb(void) {} static inline void clear_hv_tscchange_cb(void) {}
static inline void hyperv_stop_tsc_emulation(void) {}; static inline void hyperv_stop_tsc_emulation(void) {};
static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
{
return NULL;
}
#endif /* CONFIG_HYPERV */ #endif /* CONFIG_HYPERV */
#ifdef CONFIG_HYPERV_TSCPAGE #ifdef CONFIG_HYPERV_TSCPAGE