1eb914cfeSTianyu Lan // SPDX-License-Identifier: GPL-2.0
2eb914cfeSTianyu Lan
3eb914cfeSTianyu Lan /*
4eb914cfeSTianyu Lan * Hyper-V nested virtualization code.
5eb914cfeSTianyu Lan *
6eb914cfeSTianyu Lan * Copyright (C) 2018, Microsoft, Inc.
7eb914cfeSTianyu Lan *
8eb914cfeSTianyu Lan * Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
9eb914cfeSTianyu Lan */
10cc4edae4SLan Tianyu #define pr_fmt(fmt) "Hyper-V: " fmt
11eb914cfeSTianyu Lan
12eb914cfeSTianyu Lan
13eb914cfeSTianyu Lan #include <linux/types.h>
14eb914cfeSTianyu Lan #include <asm/hyperv-tlfs.h>
15eb914cfeSTianyu Lan #include <asm/mshyperv.h>
16eb914cfeSTianyu Lan #include <asm/tlbflush.h>
17eb914cfeSTianyu Lan
1860cfce4cSTianyu Lan #include <asm/trace/hyperv.h>
1960cfce4cSTianyu Lan
hyperv_flush_guest_mapping(u64 as)20eb914cfeSTianyu Lan int hyperv_flush_guest_mapping(u64 as)
21eb914cfeSTianyu Lan {
22eb914cfeSTianyu Lan struct hv_guest_mapping_flush *flush;
23eb914cfeSTianyu Lan u64 status;
24eb914cfeSTianyu Lan unsigned long flags;
25eb914cfeSTianyu Lan int ret = -ENOTSUPP;
26eb914cfeSTianyu Lan
27eb914cfeSTianyu Lan if (!hv_hypercall_pg)
28eb914cfeSTianyu Lan goto fault;
29eb914cfeSTianyu Lan
30eb914cfeSTianyu Lan local_irq_save(flags);
31eb914cfeSTianyu Lan
32*55e544e1SNischala Yelchuri flush = *this_cpu_ptr(hyperv_pcpu_input_arg);
33eb914cfeSTianyu Lan
34eb914cfeSTianyu Lan if (unlikely(!flush)) {
35eb914cfeSTianyu Lan local_irq_restore(flags);
36eb914cfeSTianyu Lan goto fault;
37eb914cfeSTianyu Lan }
38eb914cfeSTianyu Lan
39eb914cfeSTianyu Lan flush->address_space = as;
40eb914cfeSTianyu Lan flush->flags = 0;
41eb914cfeSTianyu Lan
42eb914cfeSTianyu Lan status = hv_do_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE,
43eb914cfeSTianyu Lan flush, NULL);
44eb914cfeSTianyu Lan local_irq_restore(flags);
45eb914cfeSTianyu Lan
46753ed9c9SJoseph Salisbury if (hv_result_success(status))
47eb914cfeSTianyu Lan ret = 0;
48eb914cfeSTianyu Lan
49eb914cfeSTianyu Lan fault:
5060cfce4cSTianyu Lan trace_hyperv_nested_flush_guest_mapping(as, ret);
51eb914cfeSTianyu Lan return ret;
52eb914cfeSTianyu Lan }
53eb914cfeSTianyu Lan EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping);
54cc4edae4SLan Tianyu
hyperv_fill_flush_guest_mapping_list(struct hv_guest_mapping_flush_list * flush,u64 start_gfn,u64 pages)55cc4edae4SLan Tianyu int hyperv_fill_flush_guest_mapping_list(
56cc4edae4SLan Tianyu struct hv_guest_mapping_flush_list *flush,
57cc4edae4SLan Tianyu u64 start_gfn, u64 pages)
58cc4edae4SLan Tianyu {
59cc4edae4SLan Tianyu u64 cur = start_gfn;
60cc4edae4SLan Tianyu u64 additional_pages;
61cc4edae4SLan Tianyu int gpa_n = 0;
62cc4edae4SLan Tianyu
63cc4edae4SLan Tianyu do {
64cc4edae4SLan Tianyu /*
65cc4edae4SLan Tianyu * If flush requests exceed max flush count, go back to
66cc4edae4SLan Tianyu * flush tlbs without range.
67cc4edae4SLan Tianyu */
68cc4edae4SLan Tianyu if (gpa_n >= HV_MAX_FLUSH_REP_COUNT)
69cc4edae4SLan Tianyu return -ENOSPC;
70cc4edae4SLan Tianyu
71cc4edae4SLan Tianyu additional_pages = min_t(u64, pages, HV_MAX_FLUSH_PAGES) - 1;
72cc4edae4SLan Tianyu
73cc4edae4SLan Tianyu flush->gpa_list[gpa_n].page.additional_pages = additional_pages;
74cc4edae4SLan Tianyu flush->gpa_list[gpa_n].page.largepage = false;
75cc4edae4SLan Tianyu flush->gpa_list[gpa_n].page.basepfn = cur;
76cc4edae4SLan Tianyu
77cc4edae4SLan Tianyu pages -= additional_pages + 1;
78cc4edae4SLan Tianyu cur += additional_pages + 1;
79cc4edae4SLan Tianyu gpa_n++;
80cc4edae4SLan Tianyu } while (pages > 0);
81cc4edae4SLan Tianyu
82cc4edae4SLan Tianyu return gpa_n;
83cc4edae4SLan Tianyu }
84cc4edae4SLan Tianyu EXPORT_SYMBOL_GPL(hyperv_fill_flush_guest_mapping_list);
85cc4edae4SLan Tianyu
hyperv_flush_guest_mapping_range(u64 as,hyperv_fill_flush_list_func fill_flush_list_func,void * data)86cc4edae4SLan Tianyu int hyperv_flush_guest_mapping_range(u64 as,
87cc4edae4SLan Tianyu hyperv_fill_flush_list_func fill_flush_list_func, void *data)
88cc4edae4SLan Tianyu {
89cc4edae4SLan Tianyu struct hv_guest_mapping_flush_list *flush;
90753ed9c9SJoseph Salisbury u64 status;
91cc4edae4SLan Tianyu unsigned long flags;
92cc4edae4SLan Tianyu int ret = -ENOTSUPP;
93cc4edae4SLan Tianyu int gpa_n = 0;
94cc4edae4SLan Tianyu
95cc4edae4SLan Tianyu if (!hv_hypercall_pg || !fill_flush_list_func)
96cc4edae4SLan Tianyu goto fault;
97cc4edae4SLan Tianyu
98cc4edae4SLan Tianyu local_irq_save(flags);
99cc4edae4SLan Tianyu
100*55e544e1SNischala Yelchuri flush = *this_cpu_ptr(hyperv_pcpu_input_arg);
101cc4edae4SLan Tianyu
102cc4edae4SLan Tianyu if (unlikely(!flush)) {
103cc4edae4SLan Tianyu local_irq_restore(flags);
104cc4edae4SLan Tianyu goto fault;
105cc4edae4SLan Tianyu }
106cc4edae4SLan Tianyu
107cc4edae4SLan Tianyu flush->address_space = as;
108cc4edae4SLan Tianyu flush->flags = 0;
109cc4edae4SLan Tianyu
110cc4edae4SLan Tianyu gpa_n = fill_flush_list_func(flush, data);
111cc4edae4SLan Tianyu if (gpa_n < 0) {
112cc4edae4SLan Tianyu local_irq_restore(flags);
113cc4edae4SLan Tianyu goto fault;
114cc4edae4SLan Tianyu }
115cc4edae4SLan Tianyu
116cc4edae4SLan Tianyu status = hv_do_rep_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST,
117cc4edae4SLan Tianyu gpa_n, 0, flush, NULL);
118cc4edae4SLan Tianyu
119cc4edae4SLan Tianyu local_irq_restore(flags);
120cc4edae4SLan Tianyu
121753ed9c9SJoseph Salisbury if (hv_result_success(status))
122cc4edae4SLan Tianyu ret = 0;
123cc4edae4SLan Tianyu else
124753ed9c9SJoseph Salisbury ret = hv_result(status);
125cc4edae4SLan Tianyu fault:
126cc4edae4SLan Tianyu trace_hyperv_nested_flush_guest_mapping_range(as, ret);
127cc4edae4SLan Tianyu return ret;
128cc4edae4SLan Tianyu }
129cc4edae4SLan Tianyu EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping_range);
130