Skip to content

Commit cc4edae

Browse files
Lan Tianyubonzini
authored andcommitted
x86/hyper-v: Add HvFlushGuestAddressList hypercall support
Hyper-V provides HvFlushGuestAddressList() hypercall to flush EPT tlb with specified ranges. This patch is to add the hypercall support. Reviewed-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Lan Tianyu <Tianyu.Lan@microsoft.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent a49b963 commit cc4edae

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

arch/x86/hyperv/nested.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
99
*/
10+
#define pr_fmt(fmt) "Hyper-V: " fmt
1011

1112

1213
#include <linux/types.h>
@@ -54,3 +55,82 @@ int hyperv_flush_guest_mapping(u64 as)
5455
return ret;
5556
}
5657
EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping);
58+
59+
int hyperv_fill_flush_guest_mapping_list(
60+
struct hv_guest_mapping_flush_list *flush,
61+
u64 start_gfn, u64 pages)
62+
{
63+
u64 cur = start_gfn;
64+
u64 additional_pages;
65+
int gpa_n = 0;
66+
67+
do {
68+
/*
69+
* If flush requests exceed max flush count, go back to
70+
* flush tlbs without range.
71+
*/
72+
if (gpa_n >= HV_MAX_FLUSH_REP_COUNT)
73+
return -ENOSPC;
74+
75+
additional_pages = min_t(u64, pages, HV_MAX_FLUSH_PAGES) - 1;
76+
77+
flush->gpa_list[gpa_n].page.additional_pages = additional_pages;
78+
flush->gpa_list[gpa_n].page.largepage = false;
79+
flush->gpa_list[gpa_n].page.basepfn = cur;
80+
81+
pages -= additional_pages + 1;
82+
cur += additional_pages + 1;
83+
gpa_n++;
84+
} while (pages > 0);
85+
86+
return gpa_n;
87+
}
88+
EXPORT_SYMBOL_GPL(hyperv_fill_flush_guest_mapping_list);
89+
90+
int hyperv_flush_guest_mapping_range(u64 as,
91+
hyperv_fill_flush_list_func fill_flush_list_func, void *data)
92+
{
93+
struct hv_guest_mapping_flush_list **flush_pcpu;
94+
struct hv_guest_mapping_flush_list *flush;
95+
u64 status = 0;
96+
unsigned long flags;
97+
int ret = -ENOTSUPP;
98+
int gpa_n = 0;
99+
100+
if (!hv_hypercall_pg || !fill_flush_list_func)
101+
goto fault;
102+
103+
local_irq_save(flags);
104+
105+
flush_pcpu = (struct hv_guest_mapping_flush_list **)
106+
this_cpu_ptr(hyperv_pcpu_input_arg);
107+
108+
flush = *flush_pcpu;
109+
if (unlikely(!flush)) {
110+
local_irq_restore(flags);
111+
goto fault;
112+
}
113+
114+
flush->address_space = as;
115+
flush->flags = 0;
116+
117+
gpa_n = fill_flush_list_func(flush, data);
118+
if (gpa_n < 0) {
119+
local_irq_restore(flags);
120+
goto fault;
121+
}
122+
123+
status = hv_do_rep_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST,
124+
gpa_n, 0, flush, NULL);
125+
126+
local_irq_restore(flags);
127+
128+
if (!(status & HV_HYPERCALL_RESULT_MASK))
129+
ret = 0;
130+
else
131+
ret = status;
132+
fault:
133+
trace_hyperv_nested_flush_guest_mapping_range(as, ret);
134+
return ret;
135+
}
136+
EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping_range);

arch/x86/include/asm/hyperv-tlfs.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define _ASM_X86_HYPERV_TLFS_H
1111

1212
#include <linux/types.h>
13+
#include <asm/page.h>
1314

1415
/*
1516
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
@@ -353,6 +354,7 @@ struct hv_tsc_emulation_status {
353354
#define HVCALL_POST_MESSAGE 0x005c
354355
#define HVCALL_SIGNAL_EVENT 0x005d
355356
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
357+
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
356358

357359
#define HV_X64_MSR_VP_ASSIST_PAGE_ENABLE 0x00000001
358360
#define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT 12
@@ -818,6 +820,36 @@ struct hv_guest_mapping_flush {
818820
u64 flags;
819821
} __packed;
820822

823+
/*
824+
* HV_MAX_FLUSH_PAGES = "additional_pages" + 1. It's limited
825+
* by the bitwidth of "additional_pages" in union hv_gpa_page_range.
826+
*/
827+
#define HV_MAX_FLUSH_PAGES (2048)
828+
829+
/* HvFlushGuestPhysicalAddressList hypercall */
830+
union hv_gpa_page_range {
831+
u64 address_space;
832+
struct {
833+
u64 additional_pages:11;
834+
u64 largepage:1;
835+
u64 basepfn:52;
836+
} page;
837+
};
838+
839+
/*
840+
* All input flush parameters should be in single page. The max flush
841+
* count is equal with how many entries of union hv_gpa_page_range can
842+
* be populated into the input parameter page.
843+
*/
844+
#define HV_MAX_FLUSH_REP_COUNT (PAGE_SIZE - 2 * sizeof(u64) / \
845+
sizeof(union hv_gpa_page_range))
846+
847+
struct hv_guest_mapping_flush_list {
848+
u64 address_space;
849+
u64 flags;
850+
union hv_gpa_page_range gpa_list[HV_MAX_FLUSH_REP_COUNT];
851+
};
852+
821853
/* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */
822854
struct hv_tlb_flush {
823855
u64 address_space;

arch/x86/include/asm/mshyperv.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ struct ms_hyperv_info {
2222

2323
extern struct ms_hyperv_info ms_hyperv;
2424

25+
26+
typedef int (*hyperv_fill_flush_list_func)(
27+
struct hv_guest_mapping_flush_list *flush,
28+
void *data);
29+
2530
/*
2631
* Generate the guest ID.
2732
*/
@@ -348,6 +353,11 @@ void set_hv_tscchange_cb(void (*cb)(void));
348353
void clear_hv_tscchange_cb(void);
349354
void hyperv_stop_tsc_emulation(void);
350355
int hyperv_flush_guest_mapping(u64 as);
356+
int hyperv_flush_guest_mapping_range(u64 as,
357+
hyperv_fill_flush_list_func fill_func, void *data);
358+
int hyperv_fill_flush_guest_mapping_list(
359+
struct hv_guest_mapping_flush_list *flush,
360+
u64 start_gfn, u64 end_gfn);
351361

352362
#ifdef CONFIG_X86_64
353363
void hv_apic_init(void);
@@ -370,6 +380,11 @@ static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
370380
return NULL;
371381
}
372382
static inline int hyperv_flush_guest_mapping(u64 as) { return -1; }
383+
static inline int hyperv_flush_guest_mapping_range(u64 as,
384+
hyperv_fill_flush_list_func fill_func, void *data)
385+
{
386+
return -1;
387+
}
373388
#endif /* CONFIG_HYPERV */
374389

375390
#ifdef CONFIG_HYPERV_TSCPAGE

arch/x86/include/asm/trace/hyperv.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ TRACE_EVENT(hyperv_nested_flush_guest_mapping,
4242
TP_printk("address space %llx ret %d", __entry->as, __entry->ret)
4343
);
4444

45+
TRACE_EVENT(hyperv_nested_flush_guest_mapping_range,
46+
TP_PROTO(u64 as, int ret),
47+
TP_ARGS(as, ret),
48+
49+
TP_STRUCT__entry(
50+
__field(u64, as)
51+
__field(int, ret)
52+
),
53+
TP_fast_assign(__entry->as = as;
54+
__entry->ret = ret;
55+
),
56+
TP_printk("address space %llx ret %d", __entry->as, __entry->ret)
57+
);
58+
4559
TRACE_EVENT(hyperv_send_ipi_mask,
4660
TP_PROTO(const struct cpumask *cpus,
4761
int vector),

0 commit comments

Comments
 (0)