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