1 // SPDX-License-Identifier: GPL-2.0
4 * Hyper-V nested virtualization code.
6 * Copyright (C) 2018, Microsoft, Inc.
8 * Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
10 #define pr_fmt(fmt) "Hyper-V: " fmt
13 #include <linux/types.h>
14 #include <asm/hyperv-tlfs.h>
15 #include <asm/mshyperv.h>
16 #include <asm/tlbflush.h>
18 #include <asm/trace/hyperv.h>
20 int hyperv_flush_guest_mapping(u64 as
)
22 struct hv_guest_mapping_flush
**flush_pcpu
;
23 struct hv_guest_mapping_flush
*flush
;
31 local_irq_save(flags
);
33 flush_pcpu
= (struct hv_guest_mapping_flush
**)
34 this_cpu_ptr(hyperv_pcpu_input_arg
);
38 if (unlikely(!flush
)) {
39 local_irq_restore(flags
);
43 flush
->address_space
= as
;
46 status
= hv_do_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE
,
48 local_irq_restore(flags
);
50 if (!(status
& HV_HYPERCALL_RESULT_MASK
))
54 trace_hyperv_nested_flush_guest_mapping(as
, ret
);
57 EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping
);
59 int hyperv_fill_flush_guest_mapping_list(
60 struct hv_guest_mapping_flush_list
*flush
,
61 u64 start_gfn
, u64 pages
)
69 * If flush requests exceed max flush count, go back to
70 * flush tlbs without range.
72 if (gpa_n
>= HV_MAX_FLUSH_REP_COUNT
)
75 additional_pages
= min_t(u64
, pages
, HV_MAX_FLUSH_PAGES
) - 1;
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
;
81 pages
-= additional_pages
+ 1;
82 cur
+= additional_pages
+ 1;
88 EXPORT_SYMBOL_GPL(hyperv_fill_flush_guest_mapping_list
);
90 int hyperv_flush_guest_mapping_range(u64 as
,
91 hyperv_fill_flush_list_func fill_flush_list_func
, void *data
)
93 struct hv_guest_mapping_flush_list
**flush_pcpu
;
94 struct hv_guest_mapping_flush_list
*flush
;
100 if (!hv_hypercall_pg
|| !fill_flush_list_func
)
103 local_irq_save(flags
);
105 flush_pcpu
= (struct hv_guest_mapping_flush_list
**)
106 this_cpu_ptr(hyperv_pcpu_input_arg
);
109 if (unlikely(!flush
)) {
110 local_irq_restore(flags
);
114 flush
->address_space
= as
;
117 gpa_n
= fill_flush_list_func(flush
, data
);
119 local_irq_restore(flags
);
123 status
= hv_do_rep_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST
,
124 gpa_n
, 0, flush
, NULL
);
126 local_irq_restore(flags
);
128 if (!(status
& HV_HYPERCALL_RESULT_MASK
))
133 trace_hyperv_nested_flush_guest_mapping_range(as
, ret
);
136 EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping_range
);