1 /******************************************************************************
2 * xc_misc.c
3 *
4 * Miscellaneous control interface functions.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "xc_bitops.h"
21 #include "xc_private.h"
22 #include <xen/hvm/hvm_op.h>
23
xc_get_max_cpus(xc_interface * xch)24 int xc_get_max_cpus(xc_interface *xch)
25 {
26 static int max_cpus = 0;
27 xc_physinfo_t physinfo;
28
29 if ( max_cpus )
30 return max_cpus;
31
32 if ( !xc_physinfo(xch, &physinfo) )
33 {
34 max_cpus = physinfo.max_cpu_id + 1;
35 return max_cpus;
36 }
37
38 return -1;
39 }
40
xc_get_online_cpus(xc_interface * xch)41 int xc_get_online_cpus(xc_interface *xch)
42 {
43 xc_physinfo_t physinfo;
44
45 if ( !xc_physinfo(xch, &physinfo) )
46 return physinfo.nr_cpus;
47
48 return -1;
49 }
50
xc_get_max_nodes(xc_interface * xch)51 int xc_get_max_nodes(xc_interface *xch)
52 {
53 static int max_nodes = 0;
54 xc_physinfo_t physinfo;
55
56 if ( max_nodes )
57 return max_nodes;
58
59 if ( !xc_physinfo(xch, &physinfo) )
60 {
61 max_nodes = physinfo.max_node_id + 1;
62 return max_nodes;
63 }
64
65 return -1;
66 }
67
xc_get_cpumap_size(xc_interface * xch)68 int xc_get_cpumap_size(xc_interface *xch)
69 {
70 int max_cpus = xc_get_max_cpus(xch);
71
72 if ( max_cpus < 0 )
73 return -1;
74 return (max_cpus + 7) / 8;
75 }
76
xc_get_nodemap_size(xc_interface * xch)77 int xc_get_nodemap_size(xc_interface *xch)
78 {
79 int max_nodes = xc_get_max_nodes(xch);
80
81 if ( max_nodes < 0 )
82 return -1;
83 return (max_nodes + 7) / 8;
84 }
85
xc_cpumap_alloc(xc_interface * xch)86 xc_cpumap_t xc_cpumap_alloc(xc_interface *xch)
87 {
88 int sz;
89
90 sz = xc_get_cpumap_size(xch);
91 if (sz <= 0)
92 return NULL;
93 return calloc(1, sz);
94 }
95
96 /*
97 * xc_bitops.h has macros that do this as well - however they assume that
98 * the bitmask is word aligned but xc_cpumap_t is only guaranteed to be
99 * byte aligned and so we need byte versions for architectures which do
100 * not support misaligned accesses (which is basically everyone
101 * but x86, although even on x86 it can be inefficient).
102 *
103 * NOTE: The xc_bitops macros now use byte alignment.
104 * TODO: Clean up the users of this interface.
105 */
106 #define BITS_PER_CPUMAP(map) (sizeof(*map) * 8)
107 #define CPUMAP_ENTRY(cpu, map) ((map))[(cpu) / BITS_PER_CPUMAP(map)]
108 #define CPUMAP_SHIFT(cpu, map) ((cpu) % BITS_PER_CPUMAP(map))
xc_cpumap_clearcpu(int cpu,xc_cpumap_t map)109 void xc_cpumap_clearcpu(int cpu, xc_cpumap_t map)
110 {
111 CPUMAP_ENTRY(cpu, map) &= ~(1U << CPUMAP_SHIFT(cpu, map));
112 }
113
xc_cpumap_setcpu(int cpu,xc_cpumap_t map)114 void xc_cpumap_setcpu(int cpu, xc_cpumap_t map)
115 {
116 CPUMAP_ENTRY(cpu, map) |= (1U << CPUMAP_SHIFT(cpu, map));
117 }
118
xc_cpumap_testcpu(int cpu,xc_cpumap_t map)119 int xc_cpumap_testcpu(int cpu, xc_cpumap_t map)
120 {
121 return (CPUMAP_ENTRY(cpu, map) >> CPUMAP_SHIFT(cpu, map)) & 1;
122 }
123
xc_nodemap_alloc(xc_interface * xch)124 xc_nodemap_t xc_nodemap_alloc(xc_interface *xch)
125 {
126 int sz;
127
128 sz = xc_get_nodemap_size(xch);
129 if (sz <= 0)
130 return NULL;
131 return calloc(1, sz);
132 }
133
xc_readconsolering(xc_interface * xch,char * buffer,unsigned int * pnr_chars,int clear,int incremental,uint32_t * pindex)134 int xc_readconsolering(xc_interface *xch,
135 char *buffer,
136 unsigned int *pnr_chars,
137 int clear, int incremental, uint32_t *pindex)
138 {
139 int ret;
140 unsigned int nr_chars = *pnr_chars;
141 DECLARE_SYSCTL;
142 DECLARE_HYPERCALL_BOUNCE(buffer, nr_chars, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
143
144 if ( xc_hypercall_bounce_pre(xch, buffer) )
145 return -1;
146
147 sysctl.cmd = XEN_SYSCTL_readconsole;
148 set_xen_guest_handle(sysctl.u.readconsole.buffer, buffer);
149 sysctl.u.readconsole.count = nr_chars;
150 sysctl.u.readconsole.clear = clear;
151 sysctl.u.readconsole.incremental = 0;
152 if ( pindex )
153 {
154 sysctl.u.readconsole.index = *pindex;
155 sysctl.u.readconsole.incremental = incremental;
156 }
157
158 if ( (ret = do_sysctl(xch, &sysctl)) == 0 )
159 {
160 *pnr_chars = sysctl.u.readconsole.count;
161 if ( pindex )
162 *pindex = sysctl.u.readconsole.index;
163 }
164
165 xc_hypercall_bounce_post(xch, buffer);
166
167 return ret;
168 }
169
xc_send_debug_keys(xc_interface * xch,const char * keys)170 int xc_send_debug_keys(xc_interface *xch, const char *keys)
171 {
172 int ret, len = strlen(keys);
173 DECLARE_SYSCTL;
174 DECLARE_HYPERCALL_BOUNCE_IN(keys, len);
175
176 if ( xc_hypercall_bounce_pre(xch, keys) )
177 return -1;
178
179 sysctl.cmd = XEN_SYSCTL_debug_keys;
180 set_xen_guest_handle(sysctl.u.debug_keys.keys, keys);
181 sysctl.u.debug_keys.nr_keys = len;
182
183 ret = do_sysctl(xch, &sysctl);
184
185 xc_hypercall_bounce_post(xch, keys);
186
187 return ret;
188 }
189
xc_physinfo(xc_interface * xch,xc_physinfo_t * put_info)190 int xc_physinfo(xc_interface *xch,
191 xc_physinfo_t *put_info)
192 {
193 int ret;
194 DECLARE_SYSCTL;
195
196 sysctl.cmd = XEN_SYSCTL_physinfo;
197
198 memcpy(&sysctl.u.physinfo, put_info, sizeof(*put_info));
199
200 if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
201 return ret;
202
203 memcpy(put_info, &sysctl.u.physinfo, sizeof(*put_info));
204
205 return 0;
206 }
207
xc_microcode_update(xc_interface * xch,const void * buf,size_t len)208 int xc_microcode_update(xc_interface *xch, const void *buf, size_t len)
209 {
210 int ret;
211 DECLARE_PLATFORM_OP;
212 DECLARE_HYPERCALL_BUFFER(struct xenpf_microcode_update, uc);
213
214 uc = xc_hypercall_buffer_alloc(xch, uc, len);
215 if ( uc == NULL )
216 return -1;
217
218 memcpy(uc, buf, len);
219
220 platform_op.cmd = XENPF_microcode_update;
221 platform_op.u.microcode.length = len;
222 set_xen_guest_handle(platform_op.u.microcode.data, uc);
223
224 ret = do_platform_op(xch, &platform_op);
225
226 xc_hypercall_buffer_free(xch, uc);
227
228 return ret;
229 }
230
xc_cputopoinfo(xc_interface * xch,unsigned * max_cpus,xc_cputopo_t * cputopo)231 int xc_cputopoinfo(xc_interface *xch, unsigned *max_cpus,
232 xc_cputopo_t *cputopo)
233 {
234 int ret;
235 DECLARE_SYSCTL;
236 DECLARE_HYPERCALL_BOUNCE(cputopo, *max_cpus * sizeof(*cputopo),
237 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
238
239 if ( (ret = xc_hypercall_bounce_pre(xch, cputopo)) )
240 goto out;
241
242 sysctl.u.cputopoinfo.num_cpus = *max_cpus;
243 set_xen_guest_handle(sysctl.u.cputopoinfo.cputopo, cputopo);
244
245 sysctl.cmd = XEN_SYSCTL_cputopoinfo;
246
247 if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
248 goto out;
249
250 *max_cpus = sysctl.u.cputopoinfo.num_cpus;
251
252 out:
253 xc_hypercall_bounce_post(xch, cputopo);
254
255 return ret;
256 }
257
xc_numainfo(xc_interface * xch,unsigned * max_nodes,xc_meminfo_t * meminfo,uint32_t * distance)258 int xc_numainfo(xc_interface *xch, unsigned *max_nodes,
259 xc_meminfo_t *meminfo, uint32_t *distance)
260 {
261 int ret;
262 DECLARE_SYSCTL;
263 DECLARE_HYPERCALL_BOUNCE(meminfo, *max_nodes * sizeof(*meminfo),
264 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
265 DECLARE_HYPERCALL_BOUNCE(distance,
266 *max_nodes * *max_nodes * sizeof(*distance),
267 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
268
269 if ( (ret = xc_hypercall_bounce_pre(xch, meminfo)) )
270 goto out;
271 if ((ret = xc_hypercall_bounce_pre(xch, distance)) )
272 goto out;
273
274 sysctl.u.numainfo.num_nodes = *max_nodes;
275 set_xen_guest_handle(sysctl.u.numainfo.meminfo, meminfo);
276 set_xen_guest_handle(sysctl.u.numainfo.distance, distance);
277
278 sysctl.cmd = XEN_SYSCTL_numainfo;
279
280 if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
281 goto out;
282
283 *max_nodes = sysctl.u.numainfo.num_nodes;
284
285 out:
286 xc_hypercall_bounce_post(xch, meminfo);
287 xc_hypercall_bounce_post(xch, distance);
288
289 return ret;
290 }
291
xc_pcitopoinfo(xc_interface * xch,unsigned num_devs,physdev_pci_device_t * devs,uint32_t * nodes)292 int xc_pcitopoinfo(xc_interface *xch, unsigned num_devs,
293 physdev_pci_device_t *devs,
294 uint32_t *nodes)
295 {
296 int ret = 0;
297 unsigned processed = 0;
298 DECLARE_SYSCTL;
299 DECLARE_HYPERCALL_BOUNCE(devs, num_devs * sizeof(*devs),
300 XC_HYPERCALL_BUFFER_BOUNCE_IN);
301 DECLARE_HYPERCALL_BOUNCE(nodes, num_devs* sizeof(*nodes),
302 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
303
304 if ( (ret = xc_hypercall_bounce_pre(xch, devs)) )
305 goto out;
306 if ( (ret = xc_hypercall_bounce_pre(xch, nodes)) )
307 goto out;
308
309 sysctl.cmd = XEN_SYSCTL_pcitopoinfo;
310
311 while ( processed < num_devs )
312 {
313 sysctl.u.pcitopoinfo.num_devs = num_devs - processed;
314 set_xen_guest_handle_offset(sysctl.u.pcitopoinfo.devs, devs,
315 processed);
316 set_xen_guest_handle_offset(sysctl.u.pcitopoinfo.nodes, nodes,
317 processed);
318
319 if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
320 break;
321
322 processed += sysctl.u.pcitopoinfo.num_devs;
323 }
324
325 out:
326 xc_hypercall_bounce_post(xch, devs);
327 xc_hypercall_bounce_post(xch, nodes);
328
329 return ret;
330 }
331
xc_sched_id(xc_interface * xch,int * sched_id)332 int xc_sched_id(xc_interface *xch,
333 int *sched_id)
334 {
335 int ret;
336 DECLARE_SYSCTL;
337
338 sysctl.cmd = XEN_SYSCTL_sched_id;
339
340 if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
341 return ret;
342
343 *sched_id = sysctl.u.sched_id.sched_id;
344
345 return 0;
346 }
347
348 #if defined(__i386__) || defined(__x86_64__)
xc_mca_op(xc_interface * xch,struct xen_mc * mc)349 int xc_mca_op(xc_interface *xch, struct xen_mc *mc)
350 {
351 int ret = 0;
352 DECLARE_HYPERCALL_BOUNCE(mc, sizeof(*mc), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
353
354 if ( xc_hypercall_bounce_pre(xch, mc) )
355 {
356 PERROR("Could not bounce xen_mc memory buffer");
357 return -1;
358 }
359 mc->interface_version = XEN_MCA_INTERFACE_VERSION;
360
361 ret = xencall1(xch->xcall, __HYPERVISOR_mca,
362 HYPERCALL_BUFFER_AS_ARG(mc));
363
364 xc_hypercall_bounce_post(xch, mc);
365 return ret;
366 }
367
xc_mca_op_inject_v2(xc_interface * xch,unsigned int flags,xc_cpumap_t cpumap,unsigned int nr_bits)368 int xc_mca_op_inject_v2(xc_interface *xch, unsigned int flags,
369 xc_cpumap_t cpumap, unsigned int nr_bits)
370 {
371 int ret = -1;
372 struct xen_mc mc_buf, *mc = &mc_buf;
373 struct xen_mc_inject_v2 *inject = &mc->u.mc_inject_v2;
374
375 DECLARE_HYPERCALL_BOUNCE(cpumap, 0, XC_HYPERCALL_BUFFER_BOUNCE_IN);
376 DECLARE_HYPERCALL_BOUNCE(mc, sizeof(*mc), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
377
378 memset(mc, 0, sizeof(*mc));
379
380 if ( cpumap )
381 {
382 if ( !nr_bits )
383 {
384 errno = EINVAL;
385 goto out;
386 }
387
388 HYPERCALL_BOUNCE_SET_SIZE(cpumap, (nr_bits + 7) / 8);
389 if ( xc_hypercall_bounce_pre(xch, cpumap) )
390 {
391 PERROR("Could not bounce cpumap memory buffer");
392 goto out;
393 }
394 set_xen_guest_handle(inject->cpumap.bitmap, cpumap);
395 inject->cpumap.nr_bits = nr_bits;
396 }
397
398 inject->flags = flags;
399 mc->cmd = XEN_MC_inject_v2;
400 mc->interface_version = XEN_MCA_INTERFACE_VERSION;
401
402 if ( xc_hypercall_bounce_pre(xch, mc) )
403 {
404 PERROR("Could not bounce xen_mc memory buffer");
405 goto out_free_cpumap;
406 }
407
408 ret = xencall1(xch->xcall, __HYPERVISOR_mca, HYPERCALL_BUFFER_AS_ARG(mc));
409
410 xc_hypercall_bounce_post(xch, mc);
411 out_free_cpumap:
412 if ( cpumap )
413 xc_hypercall_bounce_post(xch, cpumap);
414 out:
415 return ret;
416 }
417 #endif /* __i386__ || __x86_64__ */
418
xc_perfc_reset(xc_interface * xch)419 int xc_perfc_reset(xc_interface *xch)
420 {
421 DECLARE_SYSCTL;
422
423 sysctl.cmd = XEN_SYSCTL_perfc_op;
424 sysctl.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_reset;
425 set_xen_guest_handle(sysctl.u.perfc_op.desc, HYPERCALL_BUFFER_NULL);
426 set_xen_guest_handle(sysctl.u.perfc_op.val, HYPERCALL_BUFFER_NULL);
427
428 return do_sysctl(xch, &sysctl);
429 }
430
xc_perfc_query_number(xc_interface * xch,int * nbr_desc,int * nbr_val)431 int xc_perfc_query_number(xc_interface *xch,
432 int *nbr_desc,
433 int *nbr_val)
434 {
435 int rc;
436 DECLARE_SYSCTL;
437
438 sysctl.cmd = XEN_SYSCTL_perfc_op;
439 sysctl.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_query;
440 set_xen_guest_handle(sysctl.u.perfc_op.desc, HYPERCALL_BUFFER_NULL);
441 set_xen_guest_handle(sysctl.u.perfc_op.val, HYPERCALL_BUFFER_NULL);
442
443 rc = do_sysctl(xch, &sysctl);
444
445 if ( nbr_desc )
446 *nbr_desc = sysctl.u.perfc_op.nr_counters;
447 if ( nbr_val )
448 *nbr_val = sysctl.u.perfc_op.nr_vals;
449
450 return rc;
451 }
452
xc_perfc_query(xc_interface * xch,struct xc_hypercall_buffer * desc,struct xc_hypercall_buffer * val)453 int xc_perfc_query(xc_interface *xch,
454 struct xc_hypercall_buffer *desc,
455 struct xc_hypercall_buffer *val)
456 {
457 DECLARE_SYSCTL;
458 DECLARE_HYPERCALL_BUFFER_ARGUMENT(desc);
459 DECLARE_HYPERCALL_BUFFER_ARGUMENT(val);
460
461 sysctl.cmd = XEN_SYSCTL_perfc_op;
462 sysctl.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_query;
463 set_xen_guest_handle(sysctl.u.perfc_op.desc, desc);
464 set_xen_guest_handle(sysctl.u.perfc_op.val, val);
465
466 return do_sysctl(xch, &sysctl);
467 }
468
xc_lockprof_reset(xc_interface * xch)469 int xc_lockprof_reset(xc_interface *xch)
470 {
471 DECLARE_SYSCTL;
472
473 sysctl.cmd = XEN_SYSCTL_lockprof_op;
474 sysctl.u.lockprof_op.cmd = XEN_SYSCTL_LOCKPROF_reset;
475 set_xen_guest_handle(sysctl.u.lockprof_op.data, HYPERCALL_BUFFER_NULL);
476
477 return do_sysctl(xch, &sysctl);
478 }
479
xc_lockprof_query_number(xc_interface * xch,uint32_t * n_elems)480 int xc_lockprof_query_number(xc_interface *xch,
481 uint32_t *n_elems)
482 {
483 int rc;
484 DECLARE_SYSCTL;
485
486 sysctl.cmd = XEN_SYSCTL_lockprof_op;
487 sysctl.u.lockprof_op.max_elem = 0;
488 sysctl.u.lockprof_op.cmd = XEN_SYSCTL_LOCKPROF_query;
489 set_xen_guest_handle(sysctl.u.lockprof_op.data, HYPERCALL_BUFFER_NULL);
490
491 rc = do_sysctl(xch, &sysctl);
492
493 *n_elems = sysctl.u.lockprof_op.nr_elem;
494
495 return rc;
496 }
497
xc_lockprof_query(xc_interface * xch,uint32_t * n_elems,uint64_t * time,struct xc_hypercall_buffer * data)498 int xc_lockprof_query(xc_interface *xch,
499 uint32_t *n_elems,
500 uint64_t *time,
501 struct xc_hypercall_buffer *data)
502 {
503 int rc;
504 DECLARE_SYSCTL;
505 DECLARE_HYPERCALL_BUFFER_ARGUMENT(data);
506
507 sysctl.cmd = XEN_SYSCTL_lockprof_op;
508 sysctl.u.lockprof_op.cmd = XEN_SYSCTL_LOCKPROF_query;
509 sysctl.u.lockprof_op.max_elem = *n_elems;
510 set_xen_guest_handle(sysctl.u.lockprof_op.data, data);
511
512 rc = do_sysctl(xch, &sysctl);
513
514 *n_elems = sysctl.u.lockprof_op.nr_elem;
515
516 return rc;
517 }
518
xc_getcpuinfo(xc_interface * xch,int max_cpus,xc_cpuinfo_t * info,int * nr_cpus)519 int xc_getcpuinfo(xc_interface *xch, int max_cpus,
520 xc_cpuinfo_t *info, int *nr_cpus)
521 {
522 int rc;
523 DECLARE_SYSCTL;
524 DECLARE_HYPERCALL_BOUNCE(info, max_cpus*sizeof(*info), XC_HYPERCALL_BUFFER_BOUNCE_OUT);
525
526 if ( xc_hypercall_bounce_pre(xch, info) )
527 return -1;
528
529 sysctl.cmd = XEN_SYSCTL_getcpuinfo;
530 sysctl.u.getcpuinfo.max_cpus = max_cpus;
531 set_xen_guest_handle(sysctl.u.getcpuinfo.info, info);
532
533 rc = do_sysctl(xch, &sysctl);
534
535 xc_hypercall_bounce_post(xch, info);
536
537 if ( nr_cpus )
538 *nr_cpus = sysctl.u.getcpuinfo.nr_cpus;
539
540 return rc;
541 }
542
xc_livepatch_upload(xc_interface * xch,char * name,unsigned char * payload,uint32_t size)543 int xc_livepatch_upload(xc_interface *xch,
544 char *name,
545 unsigned char *payload,
546 uint32_t size)
547 {
548 int rc;
549 DECLARE_SYSCTL;
550 DECLARE_HYPERCALL_BUFFER(char, local);
551 DECLARE_HYPERCALL_BOUNCE(name, 0 /* later */, XC_HYPERCALL_BUFFER_BOUNCE_IN);
552 struct xen_livepatch_name def_name = { };
553
554 if ( !name || !payload )
555 {
556 errno = EINVAL;
557 return -1;
558 }
559
560 def_name.size = strlen(name) + 1;
561 if ( def_name.size > XEN_LIVEPATCH_NAME_SIZE )
562 {
563 errno = EINVAL;
564 return -1;
565 }
566
567 HYPERCALL_BOUNCE_SET_SIZE(name, def_name.size);
568
569 if ( xc_hypercall_bounce_pre(xch, name) )
570 return -1;
571
572 local = xc_hypercall_buffer_alloc(xch, local, size);
573 if ( !local )
574 {
575 xc_hypercall_bounce_post(xch, name);
576 return -1;
577 }
578 memcpy(local, payload, size);
579
580 sysctl.cmd = XEN_SYSCTL_livepatch_op;
581 sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_UPLOAD;
582 sysctl.u.livepatch.pad = 0;
583 sysctl.u.livepatch.u.upload.size = size;
584 set_xen_guest_handle(sysctl.u.livepatch.u.upload.payload, local);
585
586 sysctl.u.livepatch.u.upload.name = def_name;
587 set_xen_guest_handle(sysctl.u.livepatch.u.upload.name.name, name);
588
589 rc = do_sysctl(xch, &sysctl);
590
591 xc_hypercall_buffer_free(xch, local);
592 xc_hypercall_bounce_post(xch, name);
593
594 return rc;
595 }
596
xc_livepatch_get(xc_interface * xch,char * name,struct xen_livepatch_status * status)597 int xc_livepatch_get(xc_interface *xch,
598 char *name,
599 struct xen_livepatch_status *status)
600 {
601 int rc;
602 DECLARE_SYSCTL;
603 DECLARE_HYPERCALL_BOUNCE(name, 0 /*adjust later */, XC_HYPERCALL_BUFFER_BOUNCE_IN);
604 struct xen_livepatch_name def_name = { };
605
606 if ( !name )
607 {
608 errno = EINVAL;
609 return -1;
610 }
611
612 def_name.size = strlen(name) + 1;
613 if ( def_name.size > XEN_LIVEPATCH_NAME_SIZE )
614 {
615 errno = EINVAL;
616 return -1;
617 }
618
619 HYPERCALL_BOUNCE_SET_SIZE(name, def_name.size);
620
621 if ( xc_hypercall_bounce_pre(xch, name) )
622 return -1;
623
624 sysctl.cmd = XEN_SYSCTL_livepatch_op;
625 sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_GET;
626 sysctl.u.livepatch.pad = 0;
627
628 sysctl.u.livepatch.u.get.status.state = 0;
629 sysctl.u.livepatch.u.get.status.rc = 0;
630
631 sysctl.u.livepatch.u.get.name = def_name;
632 set_xen_guest_handle(sysctl.u.livepatch.u.get.name.name, name);
633
634 rc = do_sysctl(xch, &sysctl);
635
636 xc_hypercall_bounce_post(xch, name);
637
638 memcpy(status, &sysctl.u.livepatch.u.get.status, sizeof(*status));
639
640 return rc;
641 }
642
643 /*
644 * Get a number of available payloads and get actual total size of
645 * the payloads' name and metadata arrays.
646 *
647 * This functions is typically executed first before the xc_livepatch_list()
648 * to obtain the sizes and correctly allocate all necessary data resources.
649 *
650 * The return value is zero if the hypercall completed successfully.
651 *
652 * If there was an error performing the sysctl operation, the return value
653 * will contain the hypercall error code value.
654 */
xc_livepatch_list_get_sizes(xc_interface * xch,unsigned int * nr,uint32_t * name_total_size,uint32_t * metadata_total_size)655 int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr,
656 uint32_t *name_total_size,
657 uint32_t *metadata_total_size)
658 {
659 DECLARE_SYSCTL;
660 int rc;
661
662 if ( !nr || !name_total_size || !metadata_total_size )
663 {
664 errno = EINVAL;
665 return -1;
666 }
667
668 memset(&sysctl, 0, sizeof(sysctl));
669 sysctl.cmd = XEN_SYSCTL_livepatch_op;
670 sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_LIST;
671
672 rc = do_sysctl(xch, &sysctl);
673 if ( rc )
674 return rc;
675
676 *nr = sysctl.u.livepatch.u.list.nr;
677 *name_total_size = sysctl.u.livepatch.u.list.name_total_size;
678 *metadata_total_size = sysctl.u.livepatch.u.list.metadata_total_size;
679
680 return 0;
681 }
682
683 /*
684 * The heart of this function is to get an array of the following objects:
685 * - xen_livepatch_status_t: states and return codes of payloads
686 * - name: names of payloads
687 * - len: lengths of corresponding payloads' names
688 * - metadata: payloads' metadata
689 * - metadata_len: lengths of corresponding payloads' metadata
690 *
691 * However it is complex because it has to deal with the hypervisor
692 * returning some of the requested data or data being stale
693 * (another hypercall might alter the list).
694 *
695 * The parameters that the function expects to contain data from
696 * the hypervisor are: 'info', 'name', and 'len'. The 'done' and
697 * 'left' are also updated with the number of entries filled out
698 * and respectively the number of entries left to get from hypervisor.
699 *
700 * It is expected that the caller of this function will first issue the
701 * xc_livepatch_list_get_sizes() in order to obtain total sizes of names
702 * and all metadata as well as the current number of payload entries.
703 * The total sizes are required and supplied via the 'name_total_size' and
704 * 'metadata_total_size' parameters.
705 *
706 * The 'max' is to be provided by the caller with the maximum number of
707 * entries that 'info', 'name', 'len', 'metadata' and 'metadata_len' arrays
708 * can be filled up with.
709 *
710 * Each entry in the 'info' array is expected to be of xen_livepatch_status_t
711 * structure size.
712 *
713 * Each entry in the 'name' array may have an arbitrary size.
714 *
715 * Each entry in the 'len' array is expected to be of uint32_t size.
716 *
717 * Each entry in the 'metadata' array may have an arbitrary size.
718 *
719 * Each entry in the 'metadata_len' array is expected to be of uint32_t size.
720 *
721 * The return value is zero if the hypercall completed successfully.
722 * Note that the return value is _not_ the amount of entries filled
723 * out - that is saved in 'done'.
724 *
725 * If there was an error performing the operation, the return value
726 * will contain an negative -EXX type value. The 'done' and 'left'
727 * will contain the number of entries that had been succesfully
728 * retrieved (if any).
729 */
xc_livepatch_list(xc_interface * xch,const unsigned int max,const unsigned int start,struct xen_livepatch_status * info,char * name,uint32_t * len,const uint32_t name_total_size,char * metadata,uint32_t * metadata_len,const uint32_t metadata_total_size,unsigned int * done,unsigned int * left)730 int xc_livepatch_list(xc_interface *xch, const unsigned int max,
731 const unsigned int start,
732 struct xen_livepatch_status *info,
733 char *name, uint32_t *len,
734 const uint32_t name_total_size,
735 char *metadata, uint32_t *metadata_len,
736 const uint32_t metadata_total_size,
737 unsigned int *done, unsigned int *left)
738 {
739 int rc;
740 DECLARE_SYSCTL;
741 /* The sizes are adjusted later - hence zero. */
742 DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
743 DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
744 DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
745 DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
746 DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
747 uint32_t max_batch_sz, nr;
748 uint32_t version = 0, retries = 0;
749 uint32_t adjust = 0;
750 uint32_t name_off = 0, metadata_off = 0;
751 uint32_t name_sz, metadata_sz;
752
753 if ( !max || !info || !name || !len ||
754 !metadata || !metadata_len || !done || !left )
755 {
756 errno = EINVAL;
757 return -1;
758 }
759
760 if ( name_total_size == 0 )
761 {
762 errno = ENOENT;
763 return -1;
764 }
765
766 memset(&sysctl, 0, sizeof(sysctl));
767 sysctl.cmd = XEN_SYSCTL_livepatch_op;
768 sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_LIST;
769 sysctl.u.livepatch.u.list.idx = start;
770
771 max_batch_sz = max;
772 name_sz = name_total_size;
773 metadata_sz = metadata_total_size;
774 *done = 0;
775 *left = 0;
776 do {
777 uint32_t _name_sz, _metadata_sz;
778
779 /*
780 * The first time we go in this loop our 'max' may be bigger
781 * than what the hypervisor is comfortable with - hence the first
782 * couple of loops may adjust the number of entries we will
783 * want filled (tracked by 'nr').
784 *
785 * N.B. This is a do { } while loop and the right hand side of
786 * the conditional when adjusting will evaluate to false (as
787 * *left is set to zero before the loop. Hence we need this
788 * adjust - even if we reset it at the start of the loop.
789 */
790 if ( adjust )
791 adjust = 0; /* Used when adjusting the 'max_batch_sz' or 'retries'. */
792
793 nr = min(max - *done, max_batch_sz);
794
795 sysctl.u.livepatch.u.list.nr = nr;
796 /* Fix the size (may vary between hypercalls). */
797 HYPERCALL_BOUNCE_SET_SIZE(info, nr * sizeof(*info));
798 HYPERCALL_BOUNCE_SET_SIZE(name, name_sz);
799 HYPERCALL_BOUNCE_SET_SIZE(len, nr * sizeof(*len));
800 HYPERCALL_BOUNCE_SET_SIZE(metadata, metadata_sz);
801 HYPERCALL_BOUNCE_SET_SIZE(metadata_len, nr * sizeof(*metadata_len));
802 /* Move the pointer to proper offset into 'info'. */
803 (HYPERCALL_BUFFER(info))->ubuf = info + *done;
804 (HYPERCALL_BUFFER(name))->ubuf = name + name_off;
805 (HYPERCALL_BUFFER(len))->ubuf = len + *done;
806 (HYPERCALL_BUFFER(metadata))->ubuf = metadata + metadata_off;
807 (HYPERCALL_BUFFER(metadata_len))->ubuf = metadata_len + *done;
808 /* Allocate memory. */
809 rc = xc_hypercall_bounce_pre(xch, info);
810 if ( rc )
811 break;
812
813 rc = xc_hypercall_bounce_pre(xch, name);
814 if ( rc )
815 break;
816
817 rc = xc_hypercall_bounce_pre(xch, len);
818 if ( rc )
819 break;
820
821 rc = xc_hypercall_bounce_pre(xch, metadata);
822 if ( rc )
823 break;
824
825 rc = xc_hypercall_bounce_pre(xch, metadata_len);
826 if ( rc )
827 break;
828
829 set_xen_guest_handle(sysctl.u.livepatch.u.list.status, info);
830 set_xen_guest_handle(sysctl.u.livepatch.u.list.name, name);
831 set_xen_guest_handle(sysctl.u.livepatch.u.list.len, len);
832 set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata, metadata);
833 set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata_len, metadata_len);
834
835 rc = do_sysctl(xch, &sysctl);
836 /*
837 * From here on we MUST call xc_hypercall_bounce. If rc < 0 we
838 * end up doing it (outside the loop), so using a break is OK.
839 */
840 if ( rc < 0 && errno == E2BIG )
841 {
842 if ( max_batch_sz <= 1 )
843 break;
844 max_batch_sz >>= 1;
845 adjust = 1; /* For the loop conditional to let us loop again. */
846 /* No memory leaks! */
847 xc_hypercall_bounce_post(xch, info);
848 xc_hypercall_bounce_post(xch, name);
849 xc_hypercall_bounce_post(xch, len);
850 xc_hypercall_bounce_post(xch, metadata);
851 xc_hypercall_bounce_post(xch, metadata_len);
852 continue;
853 }
854
855 if ( rc < 0 ) /* For all other errors we bail out. */
856 break;
857
858 if ( !version )
859 version = sysctl.u.livepatch.u.list.version;
860
861 if ( sysctl.u.livepatch.u.list.version != version )
862 {
863 /* We could make this configurable as parameter? */
864 if ( retries++ > 3 )
865 {
866 rc = -1;
867 errno = EBUSY;
868 break;
869 }
870 *done = 0; /* Retry from scratch. */
871 version = sysctl.u.livepatch.u.list.version;
872 adjust = 1; /* And make sure we continue in the loop. */
873 /* No memory leaks. */
874 xc_hypercall_bounce_post(xch, info);
875 xc_hypercall_bounce_post(xch, name);
876 xc_hypercall_bounce_post(xch, len);
877 xc_hypercall_bounce_post(xch, metadata);
878 xc_hypercall_bounce_post(xch, metadata_len);
879 continue;
880 }
881
882 /* We should never hit this, but just in case. */
883 if ( rc > nr )
884 {
885 errno = EOVERFLOW; /* Overflow! */
886 rc = -1;
887 break;
888 }
889 *left = sysctl.u.livepatch.u.list.nr; /* Total remaining count. */
890 _name_sz = sysctl.u.livepatch.u.list.name_total_size; /* Total received name size. */
891 _metadata_sz = sysctl.u.livepatch.u.list.metadata_total_size; /* Total received metadata size. */
892 /* Copy only up 'rc' of data' - we could add 'min(rc,nr) if desired. */
893 HYPERCALL_BOUNCE_SET_SIZE(info, (rc * sizeof(*info)));
894 HYPERCALL_BOUNCE_SET_SIZE(name, _name_sz);
895 HYPERCALL_BOUNCE_SET_SIZE(len, (rc * sizeof(*len)));
896 HYPERCALL_BOUNCE_SET_SIZE(metadata, _metadata_sz);
897 HYPERCALL_BOUNCE_SET_SIZE(metadata_len, (rc * sizeof(*metadata_len)));
898 /* Bounce the data and free the bounce buffer. */
899 xc_hypercall_bounce_post(xch, info);
900 xc_hypercall_bounce_post(xch, name);
901 xc_hypercall_bounce_post(xch, len);
902 xc_hypercall_bounce_post(xch, metadata);
903 xc_hypercall_bounce_post(xch, metadata_len);
904
905 name_sz -= _name_sz;
906 name_off += _name_sz;
907 metadata_sz -= _metadata_sz;
908 metadata_off += _metadata_sz;
909
910 /* And update how many elements of info we have copied into. */
911 *done += rc;
912 /* Update idx. */
913 sysctl.u.livepatch.u.list.idx = *done;
914 } while ( adjust || (*done < max && *left != 0) );
915
916 if ( rc < 0 )
917 {
918 xc_hypercall_bounce_post(xch, len);
919 xc_hypercall_bounce_post(xch, name);
920 xc_hypercall_bounce_post(xch, info);
921 xc_hypercall_bounce_post(xch, metadata);
922 xc_hypercall_bounce_post(xch, metadata_len);
923 }
924
925 return rc > 0 ? 0 : rc;
926 }
927
_xc_livepatch_action(xc_interface * xch,char * name,unsigned int action,uint32_t timeout,uint32_t flags)928 static int _xc_livepatch_action(xc_interface *xch,
929 char *name,
930 unsigned int action,
931 uint32_t timeout,
932 uint32_t flags)
933 {
934 int rc;
935 DECLARE_SYSCTL;
936 /* The size is figured out when we strlen(name) */
937 DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_IN);
938 struct xen_livepatch_name def_name = { };
939
940 def_name.size = strlen(name) + 1;
941
942 if ( def_name.size > XEN_LIVEPATCH_NAME_SIZE )
943 {
944 errno = EINVAL;
945 return -1;
946 }
947
948 HYPERCALL_BOUNCE_SET_SIZE(name, def_name.size);
949
950 if ( xc_hypercall_bounce_pre(xch, name) )
951 return -1;
952
953 sysctl.cmd = XEN_SYSCTL_livepatch_op;
954 sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_ACTION;
955 sysctl.u.livepatch.pad = 0;
956 sysctl.u.livepatch.u.action.cmd = action;
957 sysctl.u.livepatch.u.action.timeout = timeout;
958 sysctl.u.livepatch.u.action.flags = flags;
959 sysctl.u.livepatch.u.action.pad = 0;
960
961 sysctl.u.livepatch.u.action.name = def_name;
962 set_xen_guest_handle(sysctl.u.livepatch.u.action.name.name, name);
963
964 rc = do_sysctl(xch, &sysctl);
965
966 xc_hypercall_bounce_post(xch, name);
967
968 return rc;
969 }
970
xc_livepatch_apply(xc_interface * xch,char * name,uint32_t timeout,uint32_t flags)971 int xc_livepatch_apply(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags)
972 {
973 return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_APPLY, timeout, flags);
974 }
975
xc_livepatch_revert(xc_interface * xch,char * name,uint32_t timeout,uint32_t flags)976 int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags)
977 {
978 return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REVERT, timeout, flags);
979 }
980
xc_livepatch_unload(xc_interface * xch,char * name,uint32_t timeout,uint32_t flags)981 int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags)
982 {
983 return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_UNLOAD, timeout, flags);
984 }
985
xc_livepatch_replace(xc_interface * xch,char * name,uint32_t timeout,uint32_t flags)986 int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags)
987 {
988 return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout, flags);
989 }
990
991 /*
992 * Local variables:
993 * mode: C
994 * c-file-style: "BSD"
995 * c-basic-offset: 4
996 * tab-width: 4
997 * indent-tabs-mode: nil
998 * End:
999 */
1000