xref: /linux/arch/x86/xen/multicalls.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xen hypercall batching.
4  *
5  * Xen allows multiple hypercalls to be issued at once, using the
6  * multicall interface.  This allows the cost of trapping into the
7  * hypervisor to be amortized over several calls.
8  *
9  * This file implements a simple interface for multicalls.  There's a
10  * per-cpu buffer of outstanding multicalls.  When you want to queue a
11  * multicall for issuing, you can allocate a multicall slot for the
12  * call and its arguments, along with storage for space which is
13  * pointed to by the arguments (for passing pointers to structures,
14  * etc).  When the multicall is actually issued, all the space for the
15  * commands and allocated memory is freed for reuse.
16  *
17  * Multicalls are flushed whenever any of the buffers get full, or
18  * when explicitly requested.  There's no way to get per-multicall
19  * return results back.  It will BUG if any of the multicalls fail.
20  *
21  * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
22  */
23 #include <linux/percpu.h>
24 #include <linux/hardirq.h>
25 #include <linux/debugfs.h>
26 #include <linux/jump_label.h>
27 #include <linux/printk.h>
28 
29 #include <asm/xen/hypercall.h>
30 
31 #include "xen-ops.h"
32 
33 #define MC_BATCH	32
34 
35 #define MC_ARGS		(MC_BATCH * 16)
36 
37 
38 struct mc_buffer {
39 	unsigned mcidx, argidx, cbidx;
40 	struct multicall_entry entries[MC_BATCH];
41 	unsigned char args[MC_ARGS];
42 	struct callback {
43 		void (*fn)(void *);
44 		void *data;
45 	} callbacks[MC_BATCH];
46 };
47 
48 struct mc_debug_data {
49 	struct multicall_entry entries[MC_BATCH];
50 	void *caller[MC_BATCH];
51 	size_t argsz[MC_BATCH];
52 	unsigned long *args[MC_BATCH];
53 };
54 
55 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
56 static struct mc_debug_data mc_debug_data_early __initdata;
57 static DEFINE_PER_CPU(struct mc_debug_data *, mc_debug_data) =
58 	&mc_debug_data_early;
59 static struct mc_debug_data __percpu *mc_debug_data_ptr;
60 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
61 
62 static struct static_key mc_debug __ro_after_init;
63 static bool mc_debug_enabled __initdata;
64 
xen_parse_mc_debug(char * arg)65 static int __init xen_parse_mc_debug(char *arg)
66 {
67 	mc_debug_enabled = true;
68 	static_key_slow_inc(&mc_debug);
69 
70 	return 0;
71 }
72 early_param("xen_mc_debug", xen_parse_mc_debug);
73 
mc_percpu_init(unsigned int cpu)74 void mc_percpu_init(unsigned int cpu)
75 {
76 	per_cpu(mc_debug_data, cpu) = per_cpu_ptr(mc_debug_data_ptr, cpu);
77 }
78 
mc_debug_enable(void)79 static int __init mc_debug_enable(void)
80 {
81 	unsigned long flags;
82 
83 	if (!mc_debug_enabled)
84 		return 0;
85 
86 	mc_debug_data_ptr = alloc_percpu(struct mc_debug_data);
87 	if (!mc_debug_data_ptr) {
88 		pr_err("xen_mc_debug inactive\n");
89 		static_key_slow_dec(&mc_debug);
90 		return -ENOMEM;
91 	}
92 
93 	/* Be careful when switching to percpu debug data. */
94 	local_irq_save(flags);
95 	xen_mc_flush();
96 	mc_percpu_init(0);
97 	local_irq_restore(flags);
98 
99 	pr_info("xen_mc_debug active\n");
100 
101 	return 0;
102 }
103 early_initcall(mc_debug_enable);
104 
105 /* Number of parameters of hypercalls used via multicalls. */
106 static const uint8_t hpcpars[] = {
107 	[__HYPERVISOR_mmu_update] = 4,
108 	[__HYPERVISOR_stack_switch] = 2,
109 	[__HYPERVISOR_fpu_taskswitch] = 1,
110 	[__HYPERVISOR_update_descriptor] = 2,
111 	[__HYPERVISOR_update_va_mapping] = 3,
112 	[__HYPERVISOR_mmuext_op] = 4,
113 };
114 
print_debug_data(struct mc_buffer * b,struct mc_debug_data * mcdb,int idx)115 static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
116 			     int idx)
117 {
118 	unsigned int arg;
119 	unsigned int opidx = mcdb->entries[idx].op & 0xff;
120 	unsigned int pars = 0;
121 
122 	pr_err("  call %2d: op=%lu result=%ld caller=%pS ", idx + 1,
123 	       mcdb->entries[idx].op, b->entries[idx].result,
124 	       mcdb->caller[idx]);
125 	if (opidx < ARRAY_SIZE(hpcpars))
126 		pars = hpcpars[opidx];
127 	if (pars) {
128 		pr_cont("pars=");
129 		for (arg = 0; arg < pars; arg++)
130 			pr_cont("%lx ", mcdb->entries[idx].args[arg]);
131 	}
132 	if (mcdb->argsz[idx]) {
133 		pr_cont("args=");
134 		for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
135 			pr_cont("%lx ", mcdb->args[idx][arg]);
136 	}
137 	pr_cont("\n");
138 }
139 
xen_mc_flush(void)140 void xen_mc_flush(void)
141 {
142 	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
143 	struct multicall_entry *mc;
144 	struct mc_debug_data *mcdb = NULL;
145 	int ret = 0;
146 	unsigned long flags;
147 	int i;
148 
149 	BUG_ON(preemptible());
150 
151 	/* Disable interrupts in case someone comes in and queues
152 	   something in the middle */
153 	local_irq_save(flags);
154 
155 	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
156 
157 	if (static_key_false(&mc_debug)) {
158 		mcdb = __this_cpu_read(mc_debug_data);
159 		memcpy(mcdb->entries, b->entries,
160 		       b->mcidx * sizeof(struct multicall_entry));
161 	}
162 
163 	switch (b->mcidx) {
164 	case 0:
165 		/* no-op */
166 		BUG_ON(b->argidx != 0);
167 		break;
168 
169 	case 1:
170 		/* Singleton multicall - bypass multicall machinery
171 		   and just do the call directly. */
172 		mc = &b->entries[0];
173 
174 		mc->result = xen_single_call(mc->op, mc->args[0], mc->args[1],
175 					     mc->args[2], mc->args[3],
176 					     mc->args[4]);
177 		ret = mc->result < 0;
178 		break;
179 
180 	default:
181 		if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
182 			BUG();
183 		for (i = 0; i < b->mcidx; i++)
184 			if (b->entries[i].result < 0)
185 				ret++;
186 	}
187 
188 	if (WARN_ON(ret)) {
189 		pr_err("%d of %d multicall(s) failed: cpu %d\n",
190 		       ret, b->mcidx, smp_processor_id());
191 		for (i = 0; i < b->mcidx; i++) {
192 			if (static_key_false(&mc_debug)) {
193 				print_debug_data(b, mcdb, i);
194 			} else if (b->entries[i].result < 0) {
195 				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\n",
196 				       i + 1,
197 				       b->entries[i].op,
198 				       b->entries[i].args[0],
199 				       b->entries[i].result);
200 			}
201 		}
202 	}
203 
204 	b->mcidx = 0;
205 	b->argidx = 0;
206 
207 	for (i = 0; i < b->cbidx; i++) {
208 		struct callback *cb = &b->callbacks[i];
209 
210 		(*cb->fn)(cb->data);
211 	}
212 	b->cbidx = 0;
213 
214 	local_irq_restore(flags);
215 }
216 
__xen_mc_entry(size_t args)217 struct multicall_space __xen_mc_entry(size_t args)
218 {
219 	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
220 	struct multicall_space ret;
221 	unsigned argidx = roundup(b->argidx, sizeof(u64));
222 
223 	trace_xen_mc_entry_alloc(args);
224 
225 	BUG_ON(preemptible());
226 	BUG_ON(b->argidx >= MC_ARGS);
227 
228 	if (unlikely(b->mcidx == MC_BATCH ||
229 		     (argidx + args) >= MC_ARGS)) {
230 		trace_xen_mc_flush_reason((b->mcidx == MC_BATCH) ?
231 					  XEN_MC_FL_BATCH : XEN_MC_FL_ARGS);
232 		xen_mc_flush();
233 		argidx = roundup(b->argidx, sizeof(u64));
234 	}
235 
236 	ret.mc = &b->entries[b->mcidx];
237 	if (static_key_false(&mc_debug)) {
238 		struct mc_debug_data *mcdb = __this_cpu_read(mc_debug_data);
239 
240 		mcdb->caller[b->mcidx] = __builtin_return_address(0);
241 		mcdb->argsz[b->mcidx] = args;
242 		mcdb->args[b->mcidx] = (unsigned long *)(&b->args[argidx]);
243 	}
244 	b->mcidx++;
245 	ret.args = &b->args[argidx];
246 	b->argidx = argidx + args;
247 
248 	BUG_ON(b->argidx >= MC_ARGS);
249 	return ret;
250 }
251 
xen_mc_extend_args(unsigned long op,size_t size)252 struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)
253 {
254 	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
255 	struct multicall_space ret = { NULL, NULL };
256 
257 	BUG_ON(preemptible());
258 	BUG_ON(b->argidx >= MC_ARGS);
259 
260 	if (unlikely(b->mcidx == 0 ||
261 		     b->entries[b->mcidx - 1].op != op)) {
262 		trace_xen_mc_extend_args(op, size, XEN_MC_XE_BAD_OP);
263 		goto out;
264 	}
265 
266 	if (unlikely((b->argidx + size) >= MC_ARGS)) {
267 		trace_xen_mc_extend_args(op, size, XEN_MC_XE_NO_SPACE);
268 		goto out;
269 	}
270 
271 	ret.mc = &b->entries[b->mcidx - 1];
272 	ret.args = &b->args[b->argidx];
273 	b->argidx += size;
274 
275 	BUG_ON(b->argidx >= MC_ARGS);
276 
277 	trace_xen_mc_extend_args(op, size, XEN_MC_XE_OK);
278 out:
279 	return ret;
280 }
281 
xen_mc_callback(void (* fn)(void *),void * data)282 void xen_mc_callback(void (*fn)(void *), void *data)
283 {
284 	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
285 	struct callback *cb;
286 
287 	if (b->cbidx == MC_BATCH) {
288 		trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK);
289 		xen_mc_flush();
290 	}
291 
292 	trace_xen_mc_callback(fn, data);
293 
294 	cb = &b->callbacks[b->cbidx++];
295 	cb->fn = fn;
296 	cb->data = data;
297 }
298