1 /******************************************************************************
2 * xc_domain.c
3 *
4 * API for manipulating and obtaining information on domains.
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 * Copyright (c) 2003, K A Fraser.
20 */
21
22 #include "xc_private.h"
23 #include "xc_core.h"
24 #include "xg_private.h"
25 #include "xg_save_restore.h"
26 #include <xen/memory.h>
27 #include <xen/hvm/hvm_op.h>
28
xc_domain_create(xc_interface * xch,uint32_t * pdomid,struct xen_domctl_createdomain * config)29 int xc_domain_create(xc_interface *xch, uint32_t *pdomid,
30 struct xen_domctl_createdomain *config)
31 {
32 int err;
33 DECLARE_DOMCTL;
34
35 domctl.cmd = XEN_DOMCTL_createdomain;
36 domctl.domain = *pdomid;
37 domctl.u.createdomain = *config;
38
39 if ( (err = do_domctl(xch, &domctl)) != 0 )
40 return err;
41
42 *pdomid = (uint16_t)domctl.domain;
43 *config = domctl.u.createdomain;
44
45 return 0;
46 }
47
xc_domain_cacheflush(xc_interface * xch,uint32_t domid,xen_pfn_t start_pfn,xen_pfn_t nr_pfns)48 int xc_domain_cacheflush(xc_interface *xch, uint32_t domid,
49 xen_pfn_t start_pfn, xen_pfn_t nr_pfns)
50 {
51 #if defined (__i386__) || defined (__x86_64__)
52 /*
53 * The x86 architecture provides cache coherency guarantees which prevent
54 * the need for this hypercall. Avoid the overhead of making a hypercall
55 * just for Xen to return -ENOSYS. It is safe to ignore this call on x86
56 * so we just return 0.
57 */
58 return 0;
59 #else
60 DECLARE_DOMCTL;
61 domctl.cmd = XEN_DOMCTL_cacheflush;
62 domctl.domain = domid;
63 domctl.u.cacheflush.start_pfn = start_pfn;
64 domctl.u.cacheflush.nr_pfns = nr_pfns;
65 return do_domctl(xch, &domctl);
66 #endif
67 }
68
xc_domain_pause(xc_interface * xch,uint32_t domid)69 int xc_domain_pause(xc_interface *xch,
70 uint32_t domid)
71 {
72 DECLARE_DOMCTL;
73 domctl.cmd = XEN_DOMCTL_pausedomain;
74 domctl.domain = domid;
75 return do_domctl(xch, &domctl);
76 }
77
78
xc_domain_unpause(xc_interface * xch,uint32_t domid)79 int xc_domain_unpause(xc_interface *xch,
80 uint32_t domid)
81 {
82 DECLARE_DOMCTL;
83 domctl.cmd = XEN_DOMCTL_unpausedomain;
84 domctl.domain = domid;
85 return do_domctl(xch, &domctl);
86 }
87
88
xc_domain_destroy(xc_interface * xch,uint32_t domid)89 int xc_domain_destroy(xc_interface *xch,
90 uint32_t domid)
91 {
92 DECLARE_DOMCTL;
93 domctl.cmd = XEN_DOMCTL_destroydomain;
94 domctl.domain = domid;
95 return do_domctl(xch, &domctl);
96 }
97
xc_domain_shutdown(xc_interface * xch,uint32_t domid,int reason)98 int xc_domain_shutdown(xc_interface *xch,
99 uint32_t domid,
100 int reason)
101 {
102 int ret = -1;
103 DECLARE_HYPERCALL_BUFFER(sched_remote_shutdown_t, arg);
104
105 arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
106 if ( arg == NULL )
107 {
108 PERROR("Could not allocate memory for xc_domain_shutdown hypercall");
109 goto out1;
110 }
111
112 arg->domain_id = domid;
113 arg->reason = reason;
114 ret = xencall2(xch->xcall, __HYPERVISOR_sched_op,
115 SCHEDOP_remote_shutdown,
116 HYPERCALL_BUFFER_AS_ARG(arg));
117
118 xc_hypercall_buffer_free(xch, arg);
119
120 out1:
121 return ret;
122 }
123
124
xc_domain_node_setaffinity(xc_interface * xch,uint32_t domid,xc_nodemap_t nodemap)125 int xc_domain_node_setaffinity(xc_interface *xch,
126 uint32_t domid,
127 xc_nodemap_t nodemap)
128 {
129 DECLARE_DOMCTL;
130 DECLARE_HYPERCALL_BUFFER(uint8_t, local);
131 int ret = -1;
132 int nodesize;
133
134 nodesize = xc_get_nodemap_size(xch);
135 if (nodesize <= 0)
136 {
137 PERROR("Could not get number of nodes");
138 goto out;
139 }
140
141 local = xc_hypercall_buffer_alloc(xch, local, nodesize);
142 if ( local == NULL )
143 {
144 PERROR("Could not allocate memory for setnodeaffinity domctl hypercall");
145 goto out;
146 }
147
148 domctl.cmd = XEN_DOMCTL_setnodeaffinity;
149 domctl.domain = domid;
150
151 memcpy(local, nodemap, nodesize);
152 set_xen_guest_handle(domctl.u.nodeaffinity.nodemap.bitmap, local);
153 domctl.u.nodeaffinity.nodemap.nr_bits = nodesize * 8;
154
155 ret = do_domctl(xch, &domctl);
156
157 xc_hypercall_buffer_free(xch, local);
158
159 out:
160 return ret;
161 }
162
xc_domain_node_getaffinity(xc_interface * xch,uint32_t domid,xc_nodemap_t nodemap)163 int xc_domain_node_getaffinity(xc_interface *xch,
164 uint32_t domid,
165 xc_nodemap_t nodemap)
166 {
167 DECLARE_DOMCTL;
168 DECLARE_HYPERCALL_BUFFER(uint8_t, local);
169 int ret = -1;
170 int nodesize;
171
172 nodesize = xc_get_nodemap_size(xch);
173 if (nodesize <= 0)
174 {
175 PERROR("Could not get number of nodes");
176 goto out;
177 }
178
179 local = xc_hypercall_buffer_alloc(xch, local, nodesize);
180 if ( local == NULL )
181 {
182 PERROR("Could not allocate memory for getnodeaffinity domctl hypercall");
183 goto out;
184 }
185
186 domctl.cmd = XEN_DOMCTL_getnodeaffinity;
187 domctl.domain = domid;
188
189 set_xen_guest_handle(domctl.u.nodeaffinity.nodemap.bitmap, local);
190 domctl.u.nodeaffinity.nodemap.nr_bits = nodesize * 8;
191
192 ret = do_domctl(xch, &domctl);
193
194 memcpy(nodemap, local, nodesize);
195
196 xc_hypercall_buffer_free(xch, local);
197
198 out:
199 return ret;
200 }
201
xc_vcpu_setaffinity(xc_interface * xch,uint32_t domid,int vcpu,xc_cpumap_t cpumap_hard_inout,xc_cpumap_t cpumap_soft_inout,uint32_t flags)202 int xc_vcpu_setaffinity(xc_interface *xch,
203 uint32_t domid,
204 int vcpu,
205 xc_cpumap_t cpumap_hard_inout,
206 xc_cpumap_t cpumap_soft_inout,
207 uint32_t flags)
208 {
209 DECLARE_DOMCTL;
210 DECLARE_HYPERCALL_BOUNCE(cpumap_hard_inout, 0,
211 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
212 DECLARE_HYPERCALL_BOUNCE(cpumap_soft_inout, 0,
213 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
214 int ret = -1;
215 int cpusize;
216
217 cpusize = xc_get_cpumap_size(xch);
218 if (cpusize <= 0)
219 {
220 PERROR("Could not get number of cpus");
221 return -1;
222 }
223
224 HYPERCALL_BOUNCE_SET_SIZE(cpumap_hard_inout, cpusize);
225 HYPERCALL_BOUNCE_SET_SIZE(cpumap_soft_inout, cpusize);
226
227 if ( xc_hypercall_bounce_pre(xch, cpumap_hard_inout) ||
228 xc_hypercall_bounce_pre(xch, cpumap_soft_inout) )
229 {
230 PERROR("Could not allocate hcall buffers for DOMCTL_setvcpuaffinity");
231 goto out;
232 }
233
234 domctl.cmd = XEN_DOMCTL_setvcpuaffinity;
235 domctl.domain = domid;
236 domctl.u.vcpuaffinity.vcpu = vcpu;
237 domctl.u.vcpuaffinity.flags = flags;
238
239 set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap,
240 cpumap_hard_inout);
241 domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
242 set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_soft.bitmap,
243 cpumap_soft_inout);
244 domctl.u.vcpuaffinity.cpumap_soft.nr_bits = cpusize * 8;
245
246 ret = do_domctl(xch, &domctl);
247
248 out:
249 xc_hypercall_bounce_post(xch, cpumap_hard_inout);
250 xc_hypercall_bounce_post(xch, cpumap_soft_inout);
251
252 return ret;
253 }
254
255
xc_vcpu_getaffinity(xc_interface * xch,uint32_t domid,int vcpu,xc_cpumap_t cpumap_hard,xc_cpumap_t cpumap_soft,uint32_t flags)256 int xc_vcpu_getaffinity(xc_interface *xch,
257 uint32_t domid,
258 int vcpu,
259 xc_cpumap_t cpumap_hard,
260 xc_cpumap_t cpumap_soft,
261 uint32_t flags)
262 {
263 DECLARE_DOMCTL;
264 DECLARE_HYPERCALL_BOUNCE(cpumap_hard, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
265 DECLARE_HYPERCALL_BOUNCE(cpumap_soft, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
266 int ret = -1;
267 int cpusize;
268
269 cpusize = xc_get_cpumap_size(xch);
270 if (cpusize <= 0)
271 {
272 PERROR("Could not get number of cpus");
273 return -1;
274 }
275
276 HYPERCALL_BOUNCE_SET_SIZE(cpumap_hard, cpusize);
277 HYPERCALL_BOUNCE_SET_SIZE(cpumap_soft, cpusize);
278
279 if ( xc_hypercall_bounce_pre(xch, cpumap_hard) ||
280 xc_hypercall_bounce_pre(xch, cpumap_soft) )
281 {
282 PERROR("Could not allocate hcall buffers for DOMCTL_getvcpuaffinity");
283 goto out;
284 }
285
286 domctl.cmd = XEN_DOMCTL_getvcpuaffinity;
287 domctl.domain = domid;
288 domctl.u.vcpuaffinity.vcpu = vcpu;
289 domctl.u.vcpuaffinity.flags = flags;
290
291 set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap,
292 cpumap_hard);
293 domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
294 set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_soft.bitmap,
295 cpumap_soft);
296 domctl.u.vcpuaffinity.cpumap_soft.nr_bits = cpusize * 8;
297
298 ret = do_domctl(xch, &domctl);
299
300 out:
301 xc_hypercall_bounce_post(xch, cpumap_hard);
302 xc_hypercall_bounce_post(xch, cpumap_soft);
303
304 return ret;
305 }
306
xc_domain_get_guest_width(xc_interface * xch,uint32_t domid,unsigned int * guest_width)307 int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid,
308 unsigned int *guest_width)
309 {
310 DECLARE_DOMCTL;
311
312 memset(&domctl, 0, sizeof(domctl));
313 domctl.domain = domid;
314 domctl.cmd = XEN_DOMCTL_get_address_size;
315
316 if ( do_domctl(xch, &domctl) != 0 )
317 return 1;
318
319 /* We want the result in bytes */
320 *guest_width = domctl.u.address_size.size / 8;
321 return 0;
322 }
323
xc_dom_vuart_init(xc_interface * xch,uint32_t type,uint32_t domid,uint32_t console_domid,xen_pfn_t gfn,evtchn_port_t * evtchn)324 int xc_dom_vuart_init(xc_interface *xch,
325 uint32_t type,
326 uint32_t domid,
327 uint32_t console_domid,
328 xen_pfn_t gfn,
329 evtchn_port_t *evtchn)
330 {
331 DECLARE_DOMCTL;
332 int rc = 0;
333
334 memset(&domctl, 0, sizeof(domctl));
335
336 domctl.cmd = XEN_DOMCTL_vuart_op;
337 domctl.domain = domid;
338 domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT;
339 domctl.u.vuart_op.type = type;
340 domctl.u.vuart_op.console_domid = console_domid;
341 domctl.u.vuart_op.gfn = gfn;
342
343 if ( (rc = do_domctl(xch, &domctl)) < 0 )
344 return rc;
345
346 *evtchn = domctl.u.vuart_op.evtchn;
347
348 return rc;
349 }
350
xc_domain_getinfo(xc_interface * xch,uint32_t first_domid,unsigned int max_doms,xc_dominfo_t * info)351 int xc_domain_getinfo(xc_interface *xch,
352 uint32_t first_domid,
353 unsigned int max_doms,
354 xc_dominfo_t *info)
355 {
356 unsigned int nr_doms;
357 uint32_t next_domid = first_domid;
358 DECLARE_DOMCTL;
359 int rc = 0;
360
361 memset(info, 0, max_doms*sizeof(xc_dominfo_t));
362
363 for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ )
364 {
365 domctl.cmd = XEN_DOMCTL_getdomaininfo;
366 domctl.domain = next_domid;
367 if ( (rc = do_domctl(xch, &domctl)) < 0 )
368 break;
369 info->domid = domctl.domain;
370
371 info->dying = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_dying);
372 info->shutdown = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_shutdown);
373 info->paused = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_paused);
374 info->blocked = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_blocked);
375 info->running = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_running);
376 info->hvm = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hvm_guest);
377 info->debugged = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_debugged);
378 info->xenstore = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_xs_domain);
379 info->hap = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hap);
380
381 info->shutdown_reason =
382 (domctl.u.getdomaininfo.flags>>XEN_DOMINF_shutdownshift) &
383 XEN_DOMINF_shutdownmask;
384
385 if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) )
386 {
387 info->shutdown = 0;
388 info->crashed = 1;
389 }
390
391 info->ssidref = domctl.u.getdomaininfo.ssidref;
392 info->nr_pages = domctl.u.getdomaininfo.tot_pages;
393 info->nr_outstanding_pages = domctl.u.getdomaininfo.outstanding_pages;
394 info->nr_shared_pages = domctl.u.getdomaininfo.shr_pages;
395 info->nr_paged_pages = domctl.u.getdomaininfo.paged_pages;
396 info->max_memkb = domctl.u.getdomaininfo.max_pages << (PAGE_SHIFT-10);
397 info->shared_info_frame = domctl.u.getdomaininfo.shared_info_frame;
398 info->cpu_time = domctl.u.getdomaininfo.cpu_time;
399 info->nr_online_vcpus = domctl.u.getdomaininfo.nr_online_vcpus;
400 info->max_vcpu_id = domctl.u.getdomaininfo.max_vcpu_id;
401 info->cpupool = domctl.u.getdomaininfo.cpupool;
402 info->arch_config = domctl.u.getdomaininfo.arch_config;
403
404 memcpy(info->handle, domctl.u.getdomaininfo.handle,
405 sizeof(xen_domain_handle_t));
406
407 next_domid = (uint16_t)domctl.domain + 1;
408 info++;
409 }
410
411 if ( nr_doms == 0 )
412 return rc;
413
414 return nr_doms;
415 }
416
xc_domain_getinfolist(xc_interface * xch,uint32_t first_domain,unsigned int max_domains,xc_domaininfo_t * info)417 int xc_domain_getinfolist(xc_interface *xch,
418 uint32_t first_domain,
419 unsigned int max_domains,
420 xc_domaininfo_t *info)
421 {
422 int ret = 0;
423 DECLARE_SYSCTL;
424 DECLARE_HYPERCALL_BOUNCE(info, max_domains*sizeof(*info), XC_HYPERCALL_BUFFER_BOUNCE_OUT);
425
426 if ( xc_hypercall_bounce_pre(xch, info) )
427 return -1;
428
429 sysctl.cmd = XEN_SYSCTL_getdomaininfolist;
430 sysctl.u.getdomaininfolist.first_domain = first_domain;
431 sysctl.u.getdomaininfolist.max_domains = max_domains;
432 set_xen_guest_handle(sysctl.u.getdomaininfolist.buffer, info);
433
434 if ( xc_sysctl(xch, &sysctl) < 0 )
435 ret = -1;
436 else
437 ret = sysctl.u.getdomaininfolist.num_domains;
438
439 xc_hypercall_bounce_post(xch, info);
440
441 return ret;
442 }
443
444 /* set broken page p2m */
xc_set_broken_page_p2m(xc_interface * xch,uint32_t domid,unsigned long pfn)445 int xc_set_broken_page_p2m(xc_interface *xch,
446 uint32_t domid,
447 unsigned long pfn)
448 {
449 int ret;
450 DECLARE_DOMCTL;
451
452 domctl.cmd = XEN_DOMCTL_set_broken_page_p2m;
453 domctl.domain = domid;
454 domctl.u.set_broken_page_p2m.pfn = pfn;
455 ret = do_domctl(xch, &domctl);
456
457 return ret ? -1 : 0;
458 }
459
460 /* get info from hvm guest for save */
xc_domain_hvm_getcontext(xc_interface * xch,uint32_t domid,uint8_t * ctxt_buf,uint32_t size)461 int xc_domain_hvm_getcontext(xc_interface *xch,
462 uint32_t domid,
463 uint8_t *ctxt_buf,
464 uint32_t size)
465 {
466 int ret;
467 DECLARE_DOMCTL;
468 DECLARE_HYPERCALL_BOUNCE(ctxt_buf, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
469
470 if ( xc_hypercall_bounce_pre(xch, ctxt_buf) )
471 return -1;
472
473 domctl.cmd = XEN_DOMCTL_gethvmcontext;
474 domctl.domain = domid;
475 domctl.u.hvmcontext.size = size;
476 set_xen_guest_handle(domctl.u.hvmcontext.buffer, ctxt_buf);
477
478 ret = do_domctl(xch, &domctl);
479
480 xc_hypercall_bounce_post(xch, ctxt_buf);
481
482 return (ret < 0 ? -1 : domctl.u.hvmcontext.size);
483 }
484
485 /* Get just one element of the HVM guest context.
486 * size must be >= HVM_SAVE_LENGTH(type) */
xc_domain_hvm_getcontext_partial(xc_interface * xch,uint32_t domid,uint16_t typecode,uint16_t instance,void * ctxt_buf,uint32_t size)487 int xc_domain_hvm_getcontext_partial(xc_interface *xch,
488 uint32_t domid,
489 uint16_t typecode,
490 uint16_t instance,
491 void *ctxt_buf,
492 uint32_t size)
493 {
494 int ret;
495 DECLARE_DOMCTL;
496 DECLARE_HYPERCALL_BOUNCE(ctxt_buf, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
497
498 if ( !ctxt_buf || xc_hypercall_bounce_pre(xch, ctxt_buf) )
499 return -1;
500
501 domctl.cmd = XEN_DOMCTL_gethvmcontext_partial;
502 domctl.domain = domid;
503 domctl.u.hvmcontext_partial.type = typecode;
504 domctl.u.hvmcontext_partial.instance = instance;
505 domctl.u.hvmcontext_partial.bufsz = size;
506 set_xen_guest_handle(domctl.u.hvmcontext_partial.buffer, ctxt_buf);
507
508 ret = do_domctl(xch, &domctl);
509
510 xc_hypercall_bounce_post(xch, ctxt_buf);
511
512 return ret ? -1 : 0;
513 }
514
515 /* set info to hvm guest for restore */
xc_domain_hvm_setcontext(xc_interface * xch,uint32_t domid,uint8_t * ctxt_buf,uint32_t size)516 int xc_domain_hvm_setcontext(xc_interface *xch,
517 uint32_t domid,
518 uint8_t *ctxt_buf,
519 uint32_t size)
520 {
521 int ret;
522 DECLARE_DOMCTL;
523 DECLARE_HYPERCALL_BOUNCE(ctxt_buf, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
524
525 if ( xc_hypercall_bounce_pre(xch, ctxt_buf) )
526 return -1;
527
528 domctl.cmd = XEN_DOMCTL_sethvmcontext;
529 domctl.domain = domid;
530 domctl.u.hvmcontext.size = size;
531 set_xen_guest_handle(domctl.u.hvmcontext.buffer, ctxt_buf);
532
533 ret = do_domctl(xch, &domctl);
534
535 xc_hypercall_bounce_post(xch, ctxt_buf);
536
537 return ret;
538 }
539
xc_vcpu_getcontext(xc_interface * xch,uint32_t domid,uint32_t vcpu,vcpu_guest_context_any_t * ctxt)540 int xc_vcpu_getcontext(xc_interface *xch,
541 uint32_t domid,
542 uint32_t vcpu,
543 vcpu_guest_context_any_t *ctxt)
544 {
545 int rc;
546 DECLARE_DOMCTL;
547 DECLARE_HYPERCALL_BOUNCE(ctxt, sizeof(vcpu_guest_context_any_t), XC_HYPERCALL_BUFFER_BOUNCE_OUT);
548
549 if ( xc_hypercall_bounce_pre(xch, ctxt) )
550 return -1;
551
552 domctl.cmd = XEN_DOMCTL_getvcpucontext;
553 domctl.domain = domid;
554 domctl.u.vcpucontext.vcpu = (uint16_t)vcpu;
555 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
556
557 rc = do_domctl(xch, &domctl);
558
559 xc_hypercall_bounce_post(xch, ctxt);
560
561 return rc;
562 }
563
xc_vcpu_get_extstate(xc_interface * xch,uint32_t domid,uint32_t vcpu,xc_vcpu_extstate_t * extstate)564 int xc_vcpu_get_extstate(xc_interface *xch,
565 uint32_t domid,
566 uint32_t vcpu,
567 xc_vcpu_extstate_t *extstate)
568 {
569 int rc = -ENODEV;
570 #if defined (__i386__) || defined(__x86_64__)
571 DECLARE_DOMCTL;
572 DECLARE_HYPERCALL_BUFFER(void, buffer);
573 bool get_state;
574
575 if ( !extstate )
576 return -EINVAL;
577
578 domctl.cmd = XEN_DOMCTL_getvcpuextstate;
579 domctl.domain = domid;
580 domctl.u.vcpuextstate.vcpu = (uint16_t)vcpu;
581 domctl.u.vcpuextstate.xfeature_mask = extstate->xfeature_mask;
582 domctl.u.vcpuextstate.size = extstate->size;
583
584 get_state = (extstate->size != 0);
585
586 if ( get_state )
587 {
588 buffer = xc_hypercall_buffer_alloc(xch, buffer, extstate->size);
589
590 if ( !buffer )
591 {
592 PERROR("Unable to allocate memory for vcpu%u's xsave context",
593 vcpu);
594 rc = -ENOMEM;
595 goto out;
596 }
597
598 set_xen_guest_handle(domctl.u.vcpuextstate.buffer, buffer);
599 }
600
601 rc = do_domctl(xch, &domctl);
602
603 if ( rc )
604 goto out;
605
606 /* A query for the size of buffer to use. */
607 if ( !extstate->size && !extstate->xfeature_mask )
608 {
609 extstate->xfeature_mask = domctl.u.vcpuextstate.xfeature_mask;
610 extstate->size = domctl.u.vcpuextstate.size;
611 goto out;
612 }
613
614 if ( get_state )
615 memcpy(extstate->buffer, buffer, extstate->size);
616
617 out:
618 if ( get_state )
619 xc_hypercall_buffer_free(xch, buffer);
620 #endif
621
622 return rc;
623 }
624
xc_watchdog(xc_interface * xch,uint32_t id,uint32_t timeout)625 int xc_watchdog(xc_interface *xch,
626 uint32_t id,
627 uint32_t timeout)
628 {
629 int ret = -1;
630 DECLARE_HYPERCALL_BUFFER(sched_watchdog_t, arg);
631
632 arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
633 if ( arg == NULL )
634 {
635 PERROR("Could not allocate memory for xc_watchdog hypercall");
636 goto out1;
637 }
638
639 arg->id = id;
640 arg->timeout = timeout;
641
642 ret = xencall2(xch->xcall, __HYPERVISOR_sched_op,
643 SCHEDOP_watchdog,
644 HYPERCALL_BUFFER_AS_ARG(arg));
645
646 xc_hypercall_buffer_free(xch, arg);
647
648 out1:
649 return ret;
650 }
651
652
xc_shadow_control(xc_interface * xch,uint32_t domid,unsigned int sop,xc_hypercall_buffer_t * dirty_bitmap,unsigned long pages,unsigned long * mb,uint32_t mode,xc_shadow_op_stats_t * stats)653 int xc_shadow_control(xc_interface *xch,
654 uint32_t domid,
655 unsigned int sop,
656 xc_hypercall_buffer_t *dirty_bitmap,
657 unsigned long pages,
658 unsigned long *mb,
659 uint32_t mode,
660 xc_shadow_op_stats_t *stats)
661 {
662 int rc;
663 DECLARE_DOMCTL;
664 DECLARE_HYPERCALL_BUFFER_ARGUMENT(dirty_bitmap);
665
666 memset(&domctl, 0, sizeof(domctl));
667
668 domctl.cmd = XEN_DOMCTL_shadow_op;
669 domctl.domain = domid;
670 domctl.u.shadow_op.op = sop;
671 domctl.u.shadow_op.pages = pages;
672 domctl.u.shadow_op.mb = mb ? *mb : 0;
673 domctl.u.shadow_op.mode = mode;
674 if (dirty_bitmap != NULL)
675 set_xen_guest_handle(domctl.u.shadow_op.dirty_bitmap,
676 dirty_bitmap);
677
678 rc = do_domctl(xch, &domctl);
679
680 if ( stats )
681 memcpy(stats, &domctl.u.shadow_op.stats,
682 sizeof(xc_shadow_op_stats_t));
683
684 if ( mb )
685 *mb = domctl.u.shadow_op.mb;
686
687 return (rc == 0) ? domctl.u.shadow_op.pages : rc;
688 }
689
xc_domain_setmaxmem(xc_interface * xch,uint32_t domid,uint64_t max_memkb)690 int xc_domain_setmaxmem(xc_interface *xch,
691 uint32_t domid,
692 uint64_t max_memkb)
693 {
694 DECLARE_DOMCTL;
695 domctl.cmd = XEN_DOMCTL_max_mem;
696 domctl.domain = domid;
697 domctl.u.max_mem.max_memkb = max_memkb;
698 return do_domctl(xch, &domctl);
699 }
700
701 #if defined(__i386__) || defined(__x86_64__)
xc_domain_set_memory_map(xc_interface * xch,uint32_t domid,struct e820entry entries[],uint32_t nr_entries)702 int xc_domain_set_memory_map(xc_interface *xch,
703 uint32_t domid,
704 struct e820entry entries[],
705 uint32_t nr_entries)
706 {
707 int rc;
708 struct xen_foreign_memory_map fmap = {
709 .domid = domid,
710 .map = { .nr_entries = nr_entries }
711 };
712 DECLARE_HYPERCALL_BOUNCE(entries, nr_entries * sizeof(struct e820entry),
713 XC_HYPERCALL_BUFFER_BOUNCE_IN);
714
715 if ( !entries || xc_hypercall_bounce_pre(xch, entries) )
716 return -1;
717
718 set_xen_guest_handle(fmap.map.buffer, entries);
719
720 rc = do_memory_op(xch, XENMEM_set_memory_map, &fmap, sizeof(fmap));
721
722 xc_hypercall_bounce_post(xch, entries);
723
724 return rc;
725 }
726
xc_get_machine_memory_map(xc_interface * xch,struct e820entry entries[],uint32_t max_entries)727 int xc_get_machine_memory_map(xc_interface *xch,
728 struct e820entry entries[],
729 uint32_t max_entries)
730 {
731 int rc;
732 struct xen_memory_map memmap = {
733 .nr_entries = max_entries
734 };
735 DECLARE_HYPERCALL_BOUNCE(entries, sizeof(struct e820entry) * max_entries,
736 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
737
738 if ( !entries || xc_hypercall_bounce_pre(xch, entries) || max_entries <= 1)
739 return -1;
740
741
742 set_xen_guest_handle(memmap.buffer, entries);
743
744 rc = do_memory_op(xch, XENMEM_machine_memory_map, &memmap, sizeof(memmap));
745
746 xc_hypercall_bounce_post(xch, entries);
747
748 return rc ? rc : memmap.nr_entries;
749 }
xc_domain_set_memmap_limit(xc_interface * xch,uint32_t domid,unsigned long map_limitkb)750 int xc_domain_set_memmap_limit(xc_interface *xch,
751 uint32_t domid,
752 unsigned long map_limitkb)
753 {
754 struct e820entry e820;
755
756 e820.addr = 0;
757 e820.size = (uint64_t)map_limitkb << 10;
758 e820.type = E820_RAM;
759
760 return xc_domain_set_memory_map(xch, domid, &e820, 1);
761 }
762 #else
xc_domain_set_memmap_limit(xc_interface * xch,uint32_t domid,unsigned long map_limitkb)763 int xc_domain_set_memmap_limit(xc_interface *xch,
764 uint32_t domid,
765 unsigned long map_limitkb)
766 {
767 PERROR("Function not implemented");
768 errno = ENOSYS;
769 return -1;
770 }
771 #endif
772
xc_reserved_device_memory_map(xc_interface * xch,uint32_t flags,uint16_t seg,uint8_t bus,uint8_t devfn,struct xen_reserved_device_memory entries[],uint32_t * max_entries)773 int xc_reserved_device_memory_map(xc_interface *xch,
774 uint32_t flags,
775 uint16_t seg,
776 uint8_t bus,
777 uint8_t devfn,
778 struct xen_reserved_device_memory entries[],
779 uint32_t *max_entries)
780 {
781 int rc;
782 struct xen_reserved_device_memory_map xrdmmap = {
783 .flags = flags,
784 .dev.pci.seg = seg,
785 .dev.pci.bus = bus,
786 .dev.pci.devfn = devfn,
787 .nr_entries = *max_entries
788 };
789 DECLARE_HYPERCALL_BOUNCE(entries,
790 sizeof(struct xen_reserved_device_memory) *
791 *max_entries, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
792
793 if ( xc_hypercall_bounce_pre(xch, entries) )
794 return -1;
795
796 set_xen_guest_handle(xrdmmap.buffer, entries);
797
798 rc = do_memory_op(xch, XENMEM_reserved_device_memory_map,
799 &xrdmmap, sizeof(xrdmmap));
800
801 xc_hypercall_bounce_post(xch, entries);
802
803 *max_entries = xrdmmap.nr_entries;
804
805 return rc;
806 }
807
xc_domain_set_time_offset(xc_interface * xch,uint32_t domid,int32_t time_offset_seconds)808 int xc_domain_set_time_offset(xc_interface *xch,
809 uint32_t domid,
810 int32_t time_offset_seconds)
811 {
812 DECLARE_DOMCTL;
813 domctl.cmd = XEN_DOMCTL_settimeoffset;
814 domctl.domain = domid;
815 domctl.u.settimeoffset.time_offset_seconds = time_offset_seconds;
816 return do_domctl(xch, &domctl);
817 }
818
xc_domain_disable_migrate(xc_interface * xch,uint32_t domid)819 int xc_domain_disable_migrate(xc_interface *xch, uint32_t domid)
820 {
821 DECLARE_DOMCTL;
822 domctl.cmd = XEN_DOMCTL_disable_migrate;
823 domctl.domain = domid;
824 domctl.u.disable_migrate.disable = 1;
825 return do_domctl(xch, &domctl);
826 }
827
xc_domain_set_tsc_info(xc_interface * xch,uint32_t domid,uint32_t tsc_mode,uint64_t elapsed_nsec,uint32_t gtsc_khz,uint32_t incarnation)828 int xc_domain_set_tsc_info(xc_interface *xch,
829 uint32_t domid,
830 uint32_t tsc_mode,
831 uint64_t elapsed_nsec,
832 uint32_t gtsc_khz,
833 uint32_t incarnation)
834 {
835 DECLARE_DOMCTL;
836 domctl.cmd = XEN_DOMCTL_settscinfo;
837 domctl.domain = domid;
838 domctl.u.tsc_info.tsc_mode = tsc_mode;
839 domctl.u.tsc_info.elapsed_nsec = elapsed_nsec;
840 domctl.u.tsc_info.gtsc_khz = gtsc_khz;
841 domctl.u.tsc_info.incarnation = incarnation;
842 return do_domctl(xch, &domctl);
843 }
844
xc_domain_get_tsc_info(xc_interface * xch,uint32_t domid,uint32_t * tsc_mode,uint64_t * elapsed_nsec,uint32_t * gtsc_khz,uint32_t * incarnation)845 int xc_domain_get_tsc_info(xc_interface *xch,
846 uint32_t domid,
847 uint32_t *tsc_mode,
848 uint64_t *elapsed_nsec,
849 uint32_t *gtsc_khz,
850 uint32_t *incarnation)
851 {
852 int rc;
853 DECLARE_DOMCTL;
854
855 domctl.cmd = XEN_DOMCTL_gettscinfo;
856 domctl.domain = domid;
857 rc = do_domctl(xch, &domctl);
858 if ( rc == 0 )
859 {
860 *tsc_mode = domctl.u.tsc_info.tsc_mode;
861 *elapsed_nsec = domctl.u.tsc_info.elapsed_nsec;
862 *gtsc_khz = domctl.u.tsc_info.gtsc_khz;
863 *incarnation = domctl.u.tsc_info.incarnation;
864 }
865 return rc;
866 }
867
868
xc_domain_maximum_gpfn(xc_interface * xch,uint32_t domid,xen_pfn_t * gpfns)869 int xc_domain_maximum_gpfn(xc_interface *xch, uint32_t domid, xen_pfn_t *gpfns)
870 {
871 long rc = do_memory_op(xch, XENMEM_maximum_gpfn, &domid, sizeof(domid));
872
873 if ( rc >= 0 )
874 {
875 *gpfns = rc;
876 rc = 0;
877 }
878 return rc;
879 }
880
xc_domain_nr_gpfns(xc_interface * xch,uint32_t domid,xen_pfn_t * gpfns)881 int xc_domain_nr_gpfns(xc_interface *xch, uint32_t domid, xen_pfn_t *gpfns)
882 {
883 int rc = xc_domain_maximum_gpfn(xch, domid, gpfns);
884
885 if ( rc >= 0 )
886 *gpfns += 1;
887
888 return rc;
889 }
890
xc_domain_increase_reservation(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,unsigned int mem_flags,xen_pfn_t * extent_start)891 int xc_domain_increase_reservation(xc_interface *xch,
892 uint32_t domid,
893 unsigned long nr_extents,
894 unsigned int extent_order,
895 unsigned int mem_flags,
896 xen_pfn_t *extent_start)
897 {
898 int err;
899 DECLARE_HYPERCALL_BOUNCE(extent_start, nr_extents * sizeof(*extent_start), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
900 struct xen_memory_reservation reservation = {
901 .nr_extents = nr_extents,
902 .extent_order = extent_order,
903 .mem_flags = mem_flags,
904 .domid = domid
905 };
906
907 /* may be NULL */
908 if ( xc_hypercall_bounce_pre(xch, extent_start) )
909 {
910 PERROR("Could not bounce memory for XENMEM_increase_reservation hypercall");
911 return -1;
912 }
913
914 set_xen_guest_handle(reservation.extent_start, extent_start);
915
916 err = do_memory_op(xch, XENMEM_increase_reservation, &reservation, sizeof(reservation));
917
918 xc_hypercall_bounce_post(xch, extent_start);
919
920 return err;
921 }
922
xc_domain_increase_reservation_exact(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,unsigned int mem_flags,xen_pfn_t * extent_start)923 int xc_domain_increase_reservation_exact(xc_interface *xch,
924 uint32_t domid,
925 unsigned long nr_extents,
926 unsigned int extent_order,
927 unsigned int mem_flags,
928 xen_pfn_t *extent_start)
929 {
930 int err;
931
932 err = xc_domain_increase_reservation(xch, domid, nr_extents,
933 extent_order, mem_flags, extent_start);
934
935 if ( err == nr_extents )
936 return 0;
937
938 if ( err >= 0 )
939 {
940 DPRINTF("Failed allocation for dom %d: "
941 "%ld extents of order %d, mem_flags %x\n",
942 domid, nr_extents, extent_order, mem_flags);
943 errno = ENOMEM;
944 err = -1;
945 }
946
947 return err;
948 }
949
xc_domain_decrease_reservation(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,xen_pfn_t * extent_start)950 int xc_domain_decrease_reservation(xc_interface *xch,
951 uint32_t domid,
952 unsigned long nr_extents,
953 unsigned int extent_order,
954 xen_pfn_t *extent_start)
955 {
956 int err;
957 DECLARE_HYPERCALL_BOUNCE(extent_start, nr_extents * sizeof(*extent_start), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
958 struct xen_memory_reservation reservation = {
959 .nr_extents = nr_extents,
960 .extent_order = extent_order,
961 .mem_flags = 0,
962 .domid = domid
963 };
964
965 if ( extent_start == NULL )
966 {
967 DPRINTF("decrease_reservation extent_start is NULL!\n");
968 errno = EINVAL;
969 return -1;
970 }
971
972 if ( xc_hypercall_bounce_pre(xch, extent_start) )
973 {
974 PERROR("Could not bounce memory for XENMEM_decrease_reservation hypercall");
975 return -1;
976 }
977 set_xen_guest_handle(reservation.extent_start, extent_start);
978
979 err = do_memory_op(xch, XENMEM_decrease_reservation, &reservation, sizeof(reservation));
980
981 xc_hypercall_bounce_post(xch, extent_start);
982
983 return err;
984 }
985
xc_domain_decrease_reservation_exact(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,xen_pfn_t * extent_start)986 int xc_domain_decrease_reservation_exact(xc_interface *xch,
987 uint32_t domid,
988 unsigned long nr_extents,
989 unsigned int extent_order,
990 xen_pfn_t *extent_start)
991 {
992 int err;
993
994 err = xc_domain_decrease_reservation(xch, domid, nr_extents,
995 extent_order, extent_start);
996
997 if ( err == nr_extents )
998 return 0;
999
1000 if ( err >= 0 )
1001 {
1002 DPRINTF("Failed deallocation for dom %d: %ld extents of order %d\n",
1003 domid, nr_extents, extent_order);
1004 errno = EINVAL;
1005 err = -1;
1006 }
1007
1008 return err;
1009 }
1010
xc_domain_add_to_physmap(xc_interface * xch,uint32_t domid,unsigned int space,unsigned long idx,xen_pfn_t gpfn)1011 int xc_domain_add_to_physmap(xc_interface *xch,
1012 uint32_t domid,
1013 unsigned int space,
1014 unsigned long idx,
1015 xen_pfn_t gpfn)
1016 {
1017 struct xen_add_to_physmap xatp = {
1018 .domid = domid,
1019 .space = space,
1020 .idx = idx,
1021 .gpfn = gpfn,
1022 };
1023 return do_memory_op(xch, XENMEM_add_to_physmap, &xatp, sizeof(xatp));
1024 }
1025
xc_domain_add_to_physmap_batch(xc_interface * xch,uint32_t domid,uint32_t foreign_domid,unsigned int space,unsigned int size,xen_ulong_t * idxs,xen_pfn_t * gpfns,int * errs)1026 int xc_domain_add_to_physmap_batch(xc_interface *xch,
1027 uint32_t domid,
1028 uint32_t foreign_domid,
1029 unsigned int space,
1030 unsigned int size,
1031 xen_ulong_t *idxs,
1032 xen_pfn_t *gpfns,
1033 int *errs)
1034 {
1035 int rc;
1036 DECLARE_HYPERCALL_BOUNCE(idxs, size * sizeof(*idxs), XC_HYPERCALL_BUFFER_BOUNCE_IN);
1037 DECLARE_HYPERCALL_BOUNCE(gpfns, size * sizeof(*gpfns), XC_HYPERCALL_BUFFER_BOUNCE_IN);
1038 DECLARE_HYPERCALL_BOUNCE(errs, size * sizeof(*errs), XC_HYPERCALL_BUFFER_BOUNCE_OUT);
1039
1040 struct xen_add_to_physmap_batch xatp_batch = {
1041 .domid = domid,
1042 .space = space,
1043 .size = size,
1044 .u = { .foreign_domid = foreign_domid }
1045 };
1046
1047 if ( xc_hypercall_bounce_pre(xch, idxs) ||
1048 xc_hypercall_bounce_pre(xch, gpfns) ||
1049 xc_hypercall_bounce_pre(xch, errs) )
1050 {
1051 PERROR("Could not bounce memory for XENMEM_add_to_physmap_batch");
1052 rc = -1;
1053 goto out;
1054 }
1055
1056 set_xen_guest_handle(xatp_batch.idxs, idxs);
1057 set_xen_guest_handle(xatp_batch.gpfns, gpfns);
1058 set_xen_guest_handle(xatp_batch.errs, errs);
1059
1060 rc = do_memory_op(xch, XENMEM_add_to_physmap_batch,
1061 &xatp_batch, sizeof(xatp_batch));
1062
1063 out:
1064 xc_hypercall_bounce_post(xch, idxs);
1065 xc_hypercall_bounce_post(xch, gpfns);
1066 xc_hypercall_bounce_post(xch, errs);
1067
1068 return rc;
1069 }
1070
xc_domain_remove_from_physmap(xc_interface * xch,uint32_t domid,xen_pfn_t gpfn)1071 int xc_domain_remove_from_physmap(xc_interface *xch,
1072 uint32_t domid,
1073 xen_pfn_t gpfn)
1074 {
1075 struct xen_remove_from_physmap xrfp = {
1076 .domid = domid,
1077 .gpfn = gpfn,
1078 };
1079 return do_memory_op(xch, XENMEM_remove_from_physmap, &xrfp, sizeof(xrfp));
1080 }
1081
xc_domain_claim_pages(xc_interface * xch,uint32_t domid,unsigned long nr_pages)1082 int xc_domain_claim_pages(xc_interface *xch,
1083 uint32_t domid,
1084 unsigned long nr_pages)
1085 {
1086 int err;
1087 struct xen_memory_reservation reservation = {
1088 .nr_extents = nr_pages,
1089 .extent_order = 0,
1090 .mem_flags = 0, /* no flags */
1091 .domid = domid
1092 };
1093
1094 set_xen_guest_handle(reservation.extent_start, HYPERCALL_BUFFER_NULL);
1095
1096 err = do_memory_op(xch, XENMEM_claim_pages, &reservation, sizeof(reservation));
1097 /* Ignore it if the hypervisor does not support the call. */
1098 if (err == -1 && errno == ENOSYS)
1099 err = errno = 0;
1100 return err;
1101 }
1102
xc_domain_populate_physmap(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,unsigned int mem_flags,xen_pfn_t * extent_start)1103 int xc_domain_populate_physmap(xc_interface *xch,
1104 uint32_t domid,
1105 unsigned long nr_extents,
1106 unsigned int extent_order,
1107 unsigned int mem_flags,
1108 xen_pfn_t *extent_start)
1109 {
1110 int err;
1111 DECLARE_HYPERCALL_BOUNCE(extent_start, nr_extents * sizeof(*extent_start), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
1112 struct xen_memory_reservation reservation = {
1113 .nr_extents = nr_extents,
1114 .extent_order = extent_order,
1115 .mem_flags = mem_flags,
1116 .domid = domid
1117 };
1118
1119 if ( xc_hypercall_bounce_pre(xch, extent_start) )
1120 {
1121 PERROR("Could not bounce memory for XENMEM_populate_physmap hypercall");
1122 return -1;
1123 }
1124 set_xen_guest_handle(reservation.extent_start, extent_start);
1125
1126 err = do_memory_op(xch, XENMEM_populate_physmap, &reservation, sizeof(reservation));
1127
1128 xc_hypercall_bounce_post(xch, extent_start);
1129 return err;
1130 }
1131
xc_domain_populate_physmap_exact(xc_interface * xch,uint32_t domid,unsigned long nr_extents,unsigned int extent_order,unsigned int mem_flags,xen_pfn_t * extent_start)1132 int xc_domain_populate_physmap_exact(xc_interface *xch,
1133 uint32_t domid,
1134 unsigned long nr_extents,
1135 unsigned int extent_order,
1136 unsigned int mem_flags,
1137 xen_pfn_t *extent_start)
1138 {
1139 int err;
1140
1141 err = xc_domain_populate_physmap(xch, domid, nr_extents,
1142 extent_order, mem_flags, extent_start);
1143 if ( err == nr_extents )
1144 return 0;
1145
1146 if ( err >= 0 )
1147 {
1148 DPRINTF("Failed allocation for dom %d: %ld extents of order %d\n",
1149 domid, nr_extents, extent_order);
1150 errno = EBUSY;
1151 err = -1;
1152 }
1153
1154 return err;
1155 }
1156
xc_domain_memory_exchange_pages(xc_interface * xch,uint32_t domid,unsigned long nr_in_extents,unsigned int in_order,xen_pfn_t * in_extents,unsigned long nr_out_extents,unsigned int out_order,xen_pfn_t * out_extents)1157 int xc_domain_memory_exchange_pages(xc_interface *xch,
1158 uint32_t domid,
1159 unsigned long nr_in_extents,
1160 unsigned int in_order,
1161 xen_pfn_t *in_extents,
1162 unsigned long nr_out_extents,
1163 unsigned int out_order,
1164 xen_pfn_t *out_extents)
1165 {
1166 int rc = -1;
1167 DECLARE_HYPERCALL_BOUNCE(in_extents, nr_in_extents*sizeof(*in_extents), XC_HYPERCALL_BUFFER_BOUNCE_IN);
1168 DECLARE_HYPERCALL_BOUNCE(out_extents, nr_out_extents*sizeof(*out_extents), XC_HYPERCALL_BUFFER_BOUNCE_OUT);
1169 struct xen_memory_exchange exchange = {
1170 .in = {
1171 .nr_extents = nr_in_extents,
1172 .extent_order = in_order,
1173 .domid = domid
1174 },
1175 .out = {
1176 .nr_extents = nr_out_extents,
1177 .extent_order = out_order,
1178 .domid = domid
1179 }
1180 };
1181
1182 if ( xc_hypercall_bounce_pre(xch, in_extents) ||
1183 xc_hypercall_bounce_pre(xch, out_extents))
1184 goto out;
1185
1186 set_xen_guest_handle(exchange.in.extent_start, in_extents);
1187 set_xen_guest_handle(exchange.out.extent_start, out_extents);
1188
1189 rc = do_memory_op(xch, XENMEM_exchange, &exchange, sizeof(exchange));
1190
1191 out:
1192 xc_hypercall_bounce_post(xch, in_extents);
1193 xc_hypercall_bounce_post(xch, out_extents);
1194
1195 return rc;
1196 }
1197
1198 /* Currently only implemented on x86. This cannot be handled in the
1199 * caller, e.g. by looking for errno==ENOSYS because of the broken
1200 * error reporting style. Once this is fixed then this condition can
1201 * be removed.
1202 */
1203 #if defined(__i386__)||defined(__x86_64__)
xc_domain_pod_target(xc_interface * xch,int op,uint32_t domid,uint64_t target_pages,uint64_t * tot_pages,uint64_t * pod_cache_pages,uint64_t * pod_entries)1204 static int xc_domain_pod_target(xc_interface *xch,
1205 int op,
1206 uint32_t domid,
1207 uint64_t target_pages,
1208 uint64_t *tot_pages,
1209 uint64_t *pod_cache_pages,
1210 uint64_t *pod_entries)
1211 {
1212 int err;
1213
1214 struct xen_pod_target pod_target = {
1215 .domid = domid,
1216 .target_pages = target_pages
1217 };
1218
1219 err = do_memory_op(xch, op, &pod_target, sizeof(pod_target));
1220
1221 if ( err < 0 )
1222 {
1223 DPRINTF("Failed %s_pod_target dom %d\n",
1224 (op==XENMEM_set_pod_target)?"set":"get",
1225 domid);
1226 errno = -err;
1227 err = -1;
1228 }
1229 else
1230 err = 0;
1231
1232 if ( tot_pages )
1233 *tot_pages = pod_target.tot_pages;
1234 if ( pod_cache_pages )
1235 *pod_cache_pages = pod_target.pod_cache_pages;
1236 if ( pod_entries )
1237 *pod_entries = pod_target.pod_entries;
1238
1239 return err;
1240 }
1241
1242
xc_domain_set_pod_target(xc_interface * xch,uint32_t domid,uint64_t target_pages,uint64_t * tot_pages,uint64_t * pod_cache_pages,uint64_t * pod_entries)1243 int xc_domain_set_pod_target(xc_interface *xch,
1244 uint32_t domid,
1245 uint64_t target_pages,
1246 uint64_t *tot_pages,
1247 uint64_t *pod_cache_pages,
1248 uint64_t *pod_entries)
1249 {
1250 return xc_domain_pod_target(xch,
1251 XENMEM_set_pod_target,
1252 domid,
1253 target_pages,
1254 tot_pages,
1255 pod_cache_pages,
1256 pod_entries);
1257 }
1258
xc_domain_get_pod_target(xc_interface * xch,uint32_t domid,uint64_t * tot_pages,uint64_t * pod_cache_pages,uint64_t * pod_entries)1259 int xc_domain_get_pod_target(xc_interface *xch,
1260 uint32_t domid,
1261 uint64_t *tot_pages,
1262 uint64_t *pod_cache_pages,
1263 uint64_t *pod_entries)
1264 {
1265 return xc_domain_pod_target(xch,
1266 XENMEM_get_pod_target,
1267 domid,
1268 -1,
1269 tot_pages,
1270 pod_cache_pages,
1271 pod_entries);
1272 }
1273 #else
xc_domain_set_pod_target(xc_interface * xch,uint32_t domid,uint64_t target_pages,uint64_t * tot_pages,uint64_t * pod_cache_pages,uint64_t * pod_entries)1274 int xc_domain_set_pod_target(xc_interface *xch,
1275 uint32_t domid,
1276 uint64_t target_pages,
1277 uint64_t *tot_pages,
1278 uint64_t *pod_cache_pages,
1279 uint64_t *pod_entries)
1280 {
1281 return 0;
1282 }
xc_domain_get_pod_target(xc_interface * xch,uint32_t domid,uint64_t * tot_pages,uint64_t * pod_cache_pages,uint64_t * pod_entries)1283 int xc_domain_get_pod_target(xc_interface *xch,
1284 uint32_t domid,
1285 uint64_t *tot_pages,
1286 uint64_t *pod_cache_pages,
1287 uint64_t *pod_entries)
1288 {
1289 /* On x86 (above) xc_domain_pod_target will incorrectly return -1
1290 * with errno==-1 on error. Do the same for least surprise. */
1291 errno = -1;
1292 return -1;
1293 }
1294 #endif
1295
xc_domain_max_vcpus(xc_interface * xch,uint32_t domid,unsigned int max)1296 int xc_domain_max_vcpus(xc_interface *xch, uint32_t domid, unsigned int max)
1297 {
1298 DECLARE_DOMCTL;
1299 domctl.cmd = XEN_DOMCTL_max_vcpus;
1300 domctl.domain = domid;
1301 domctl.u.max_vcpus.max = max;
1302 return do_domctl(xch, &domctl);
1303 }
1304
xc_domain_sethandle(xc_interface * xch,uint32_t domid,xen_domain_handle_t handle)1305 int xc_domain_sethandle(xc_interface *xch, uint32_t domid,
1306 xen_domain_handle_t handle)
1307 {
1308 DECLARE_DOMCTL;
1309 domctl.cmd = XEN_DOMCTL_setdomainhandle;
1310 domctl.domain = domid;
1311 memcpy(domctl.u.setdomainhandle.handle, handle,
1312 sizeof(xen_domain_handle_t));
1313 return do_domctl(xch, &domctl);
1314 }
1315
xc_vcpu_getinfo(xc_interface * xch,uint32_t domid,uint32_t vcpu,xc_vcpuinfo_t * info)1316 int xc_vcpu_getinfo(xc_interface *xch,
1317 uint32_t domid,
1318 uint32_t vcpu,
1319 xc_vcpuinfo_t *info)
1320 {
1321 int rc;
1322 DECLARE_DOMCTL;
1323
1324 domctl.cmd = XEN_DOMCTL_getvcpuinfo;
1325 domctl.domain = domid;
1326 domctl.u.getvcpuinfo.vcpu = (uint16_t)vcpu;
1327
1328 rc = do_domctl(xch, &domctl);
1329
1330 memcpy(info, &domctl.u.getvcpuinfo, sizeof(*info));
1331
1332 return rc;
1333 }
1334
xc_domain_ioport_permission(xc_interface * xch,uint32_t domid,uint32_t first_port,uint32_t nr_ports,uint32_t allow_access)1335 int xc_domain_ioport_permission(xc_interface *xch,
1336 uint32_t domid,
1337 uint32_t first_port,
1338 uint32_t nr_ports,
1339 uint32_t allow_access)
1340 {
1341 DECLARE_DOMCTL;
1342
1343 domctl.cmd = XEN_DOMCTL_ioport_permission;
1344 domctl.domain = domid;
1345 domctl.u.ioport_permission.first_port = first_port;
1346 domctl.u.ioport_permission.nr_ports = nr_ports;
1347 domctl.u.ioport_permission.allow_access = allow_access;
1348
1349 return do_domctl(xch, &domctl);
1350 }
1351
xc_availheap(xc_interface * xch,int min_width,int max_width,int node,uint64_t * bytes)1352 int xc_availheap(xc_interface *xch,
1353 int min_width,
1354 int max_width,
1355 int node,
1356 uint64_t *bytes)
1357 {
1358 DECLARE_SYSCTL;
1359 int rc;
1360
1361 sysctl.cmd = XEN_SYSCTL_availheap;
1362 sysctl.u.availheap.min_bitwidth = min_width;
1363 sysctl.u.availheap.max_bitwidth = max_width;
1364 sysctl.u.availheap.node = node;
1365
1366 rc = xc_sysctl(xch, &sysctl);
1367
1368 *bytes = sysctl.u.availheap.avail_bytes;
1369
1370 return rc;
1371 }
1372
xc_vcpu_setcontext(xc_interface * xch,uint32_t domid,uint32_t vcpu,vcpu_guest_context_any_t * ctxt)1373 int xc_vcpu_setcontext(xc_interface *xch,
1374 uint32_t domid,
1375 uint32_t vcpu,
1376 vcpu_guest_context_any_t *ctxt)
1377 {
1378 DECLARE_DOMCTL;
1379 DECLARE_HYPERCALL_BOUNCE(ctxt, sizeof(vcpu_guest_context_any_t), XC_HYPERCALL_BUFFER_BOUNCE_IN);
1380 int rc;
1381
1382 if ( xc_hypercall_bounce_pre(xch, ctxt) )
1383 return -1;
1384
1385 domctl.cmd = XEN_DOMCTL_setvcpucontext;
1386 domctl.domain = domid;
1387 domctl.u.vcpucontext.vcpu = vcpu;
1388 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
1389
1390 rc = do_domctl(xch, &domctl);
1391
1392 xc_hypercall_bounce_post(xch, ctxt);
1393
1394 return rc;
1395 }
1396
xc_domain_irq_permission(xc_interface * xch,uint32_t domid,uint8_t pirq,uint8_t allow_access)1397 int xc_domain_irq_permission(xc_interface *xch,
1398 uint32_t domid,
1399 uint8_t pirq,
1400 uint8_t allow_access)
1401 {
1402 DECLARE_DOMCTL;
1403
1404 domctl.cmd = XEN_DOMCTL_irq_permission;
1405 domctl.domain = domid;
1406 domctl.u.irq_permission.pirq = pirq;
1407 domctl.u.irq_permission.allow_access = allow_access;
1408
1409 return do_domctl(xch, &domctl);
1410 }
1411
xc_domain_iomem_permission(xc_interface * xch,uint32_t domid,unsigned long first_mfn,unsigned long nr_mfns,uint8_t allow_access)1412 int xc_domain_iomem_permission(xc_interface *xch,
1413 uint32_t domid,
1414 unsigned long first_mfn,
1415 unsigned long nr_mfns,
1416 uint8_t allow_access)
1417 {
1418 DECLARE_DOMCTL;
1419
1420 domctl.cmd = XEN_DOMCTL_iomem_permission;
1421 domctl.domain = domid;
1422 domctl.u.iomem_permission.first_mfn = first_mfn;
1423 domctl.u.iomem_permission.nr_mfns = nr_mfns;
1424 domctl.u.iomem_permission.allow_access = allow_access;
1425
1426 return do_domctl(xch, &domctl);
1427 }
1428
xc_domain_send_trigger(xc_interface * xch,uint32_t domid,uint32_t trigger,uint32_t vcpu)1429 int xc_domain_send_trigger(xc_interface *xch,
1430 uint32_t domid,
1431 uint32_t trigger,
1432 uint32_t vcpu)
1433 {
1434 DECLARE_DOMCTL;
1435
1436 domctl.cmd = XEN_DOMCTL_sendtrigger;
1437 domctl.domain = domid;
1438 domctl.u.sendtrigger.trigger = trigger;
1439 domctl.u.sendtrigger.vcpu = vcpu;
1440
1441 return do_domctl(xch, &domctl);
1442 }
1443
xc_hvm_param_set(xc_interface * handle,uint32_t dom,uint32_t param,uint64_t value)1444 int xc_hvm_param_set(xc_interface *handle, uint32_t dom, uint32_t param, uint64_t value)
1445 {
1446 DECLARE_HYPERCALL_BUFFER(xen_hvm_param_t, arg);
1447 int rc;
1448
1449 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
1450 if ( arg == NULL )
1451 return -1;
1452
1453 arg->domid = dom;
1454 arg->index = param;
1455 arg->value = value;
1456 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op,
1457 HVMOP_set_param,
1458 HYPERCALL_BUFFER_AS_ARG(arg));
1459 xc_hypercall_buffer_free(handle, arg);
1460 return rc;
1461 }
1462
xc_hvm_param_get(xc_interface * handle,uint32_t dom,uint32_t param,uint64_t * value)1463 int xc_hvm_param_get(xc_interface *handle, uint32_t dom, uint32_t param, uint64_t *value)
1464 {
1465 DECLARE_HYPERCALL_BUFFER(xen_hvm_param_t, arg);
1466 int rc;
1467
1468 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
1469 if ( arg == NULL )
1470 return -1;
1471
1472 arg->domid = dom;
1473 arg->index = param;
1474 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op,
1475 HVMOP_get_param,
1476 HYPERCALL_BUFFER_AS_ARG(arg));
1477 *value = arg->value;
1478 xc_hypercall_buffer_free(handle, arg);
1479 return rc;
1480 }
1481
xc_set_hvm_param(xc_interface * handle,uint32_t dom,int param,unsigned long value)1482 int xc_set_hvm_param(xc_interface *handle, uint32_t dom, int param, unsigned long value)
1483 {
1484 return xc_hvm_param_set(handle, dom, param, value);
1485 }
1486
xc_get_hvm_param(xc_interface * handle,uint32_t dom,int param,unsigned long * value)1487 int xc_get_hvm_param(xc_interface *handle, uint32_t dom, int param, unsigned long *value)
1488 {
1489 uint64_t v;
1490 int ret;
1491
1492 ret = xc_hvm_param_get(handle, dom, param, &v);
1493 if (ret < 0)
1494 return ret;
1495 *value = v;
1496 return 0;
1497 }
1498
xc_domain_setdebugging(xc_interface * xch,uint32_t domid,unsigned int enable)1499 int xc_domain_setdebugging(xc_interface *xch,
1500 uint32_t domid,
1501 unsigned int enable)
1502 {
1503 DECLARE_DOMCTL;
1504
1505 domctl.cmd = XEN_DOMCTL_setdebugging;
1506 domctl.domain = domid;
1507 domctl.u.setdebugging.enable = enable;
1508 return do_domctl(xch, &domctl);
1509 }
1510
xc_assign_device(xc_interface * xch,uint32_t domid,uint32_t machine_sbdf,uint32_t flags)1511 int xc_assign_device(
1512 xc_interface *xch,
1513 uint32_t domid,
1514 uint32_t machine_sbdf,
1515 uint32_t flags)
1516 {
1517 DECLARE_DOMCTL;
1518
1519 domctl.cmd = XEN_DOMCTL_assign_device;
1520 domctl.domain = domid;
1521 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
1522 domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
1523 domctl.u.assign_device.flags = flags;
1524
1525 return do_domctl(xch, &domctl);
1526 }
1527
xc_get_device_group(xc_interface * xch,uint32_t domid,uint32_t machine_sbdf,uint32_t max_sdevs,uint32_t * num_sdevs,uint32_t * sdev_array)1528 int xc_get_device_group(
1529 xc_interface *xch,
1530 uint32_t domid,
1531 uint32_t machine_sbdf,
1532 uint32_t max_sdevs,
1533 uint32_t *num_sdevs,
1534 uint32_t *sdev_array)
1535 {
1536 int rc;
1537 DECLARE_DOMCTL;
1538 DECLARE_HYPERCALL_BOUNCE(sdev_array, max_sdevs * sizeof(*sdev_array), XC_HYPERCALL_BUFFER_BOUNCE_IN);
1539
1540 if ( xc_hypercall_bounce_pre(xch, sdev_array) )
1541 {
1542 PERROR("Could not bounce buffer for xc_get_device_group");
1543 return -1;
1544 }
1545
1546 domctl.cmd = XEN_DOMCTL_get_device_group;
1547 domctl.domain = domid;
1548
1549 domctl.u.get_device_group.machine_sbdf = machine_sbdf;
1550 domctl.u.get_device_group.max_sdevs = max_sdevs;
1551
1552 set_xen_guest_handle(domctl.u.get_device_group.sdev_array, sdev_array);
1553
1554 rc = do_domctl(xch, &domctl);
1555
1556 *num_sdevs = domctl.u.get_device_group.num_sdevs;
1557
1558 xc_hypercall_bounce_post(xch, sdev_array);
1559
1560 return rc;
1561 }
1562
xc_test_assign_device(xc_interface * xch,uint32_t domid,uint32_t machine_sbdf)1563 int xc_test_assign_device(
1564 xc_interface *xch,
1565 uint32_t domid,
1566 uint32_t machine_sbdf)
1567 {
1568 DECLARE_DOMCTL;
1569
1570 domctl.cmd = XEN_DOMCTL_test_assign_device;
1571 domctl.domain = domid;
1572 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
1573 domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
1574 domctl.u.assign_device.flags = 0;
1575
1576 return do_domctl(xch, &domctl);
1577 }
1578
xc_deassign_device(xc_interface * xch,uint32_t domid,uint32_t machine_sbdf)1579 int xc_deassign_device(
1580 xc_interface *xch,
1581 uint32_t domid,
1582 uint32_t machine_sbdf)
1583 {
1584 DECLARE_DOMCTL;
1585
1586 domctl.cmd = XEN_DOMCTL_deassign_device;
1587 domctl.domain = domid;
1588 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
1589 domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
1590 domctl.u.assign_device.flags = 0;
1591
1592 return do_domctl(xch, &domctl);
1593 }
1594
xc_assign_dt_device(xc_interface * xch,uint32_t domid,char * path)1595 int xc_assign_dt_device(
1596 xc_interface *xch,
1597 uint32_t domid,
1598 char *path)
1599 {
1600 int rc;
1601 size_t size = strlen(path);
1602 DECLARE_DOMCTL;
1603 DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
1604
1605 if ( xc_hypercall_bounce_pre(xch, path) )
1606 return -1;
1607
1608 domctl.cmd = XEN_DOMCTL_assign_device;
1609 domctl.domain = domid;
1610
1611 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
1612 domctl.u.assign_device.u.dt.size = size;
1613 /*
1614 * DT doesn't own any RDM so actually DT has nothing to do
1615 * for any flag and here just fix that as 0.
1616 */
1617 domctl.u.assign_device.flags = 0;
1618 set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
1619
1620 rc = do_domctl(xch, &domctl);
1621
1622 xc_hypercall_bounce_post(xch, path);
1623
1624 return rc;
1625 }
1626
xc_test_assign_dt_device(xc_interface * xch,uint32_t domid,char * path)1627 int xc_test_assign_dt_device(
1628 xc_interface *xch,
1629 uint32_t domid,
1630 char *path)
1631 {
1632 int rc;
1633 size_t size = strlen(path);
1634 DECLARE_DOMCTL;
1635 DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
1636
1637 if ( xc_hypercall_bounce_pre(xch, path) )
1638 return -1;
1639
1640 domctl.cmd = XEN_DOMCTL_test_assign_device;
1641 domctl.domain = domid;
1642
1643 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
1644 domctl.u.assign_device.u.dt.size = size;
1645 set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
1646 domctl.u.assign_device.flags = 0;
1647
1648 rc = do_domctl(xch, &domctl);
1649
1650 xc_hypercall_bounce_post(xch, path);
1651
1652 return rc;
1653 }
1654
xc_deassign_dt_device(xc_interface * xch,uint32_t domid,char * path)1655 int xc_deassign_dt_device(
1656 xc_interface *xch,
1657 uint32_t domid,
1658 char *path)
1659 {
1660 int rc;
1661 size_t size = strlen(path);
1662 DECLARE_DOMCTL;
1663 DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
1664
1665 if ( xc_hypercall_bounce_pre(xch, path) )
1666 return -1;
1667
1668 domctl.cmd = XEN_DOMCTL_deassign_device;
1669 domctl.domain = domid;
1670
1671 domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
1672 domctl.u.assign_device.u.dt.size = size;
1673 set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
1674 domctl.u.assign_device.flags = 0;
1675
1676 rc = do_domctl(xch, &domctl);
1677
1678 xc_hypercall_bounce_post(xch, path);
1679
1680 return rc;
1681 }
1682
1683
1684
1685
xc_domain_update_msi_irq(xc_interface * xch,uint32_t domid,uint32_t gvec,uint32_t pirq,uint32_t gflags,uint64_t gtable)1686 int xc_domain_update_msi_irq(
1687 xc_interface *xch,
1688 uint32_t domid,
1689 uint32_t gvec,
1690 uint32_t pirq,
1691 uint32_t gflags,
1692 uint64_t gtable)
1693 {
1694 int rc;
1695 struct xen_domctl_bind_pt_irq *bind;
1696 DECLARE_DOMCTL;
1697
1698 domctl.cmd = XEN_DOMCTL_bind_pt_irq;
1699 domctl.domain = domid;
1700
1701 bind = &(domctl.u.bind_pt_irq);
1702 bind->irq_type = PT_IRQ_TYPE_MSI;
1703 bind->machine_irq = pirq;
1704 bind->u.msi.gvec = gvec;
1705 bind->u.msi.gflags = gflags;
1706 bind->u.msi.gtable = gtable;
1707
1708 rc = do_domctl(xch, &domctl);
1709 return rc;
1710 }
1711
xc_domain_unbind_msi_irq(xc_interface * xch,uint32_t domid,uint32_t gvec,uint32_t pirq,uint32_t gflags)1712 int xc_domain_unbind_msi_irq(
1713 xc_interface *xch,
1714 uint32_t domid,
1715 uint32_t gvec,
1716 uint32_t pirq,
1717 uint32_t gflags)
1718 {
1719 int rc;
1720 struct xen_domctl_bind_pt_irq *bind;
1721 DECLARE_DOMCTL;
1722
1723 domctl.cmd = XEN_DOMCTL_unbind_pt_irq;
1724 domctl.domain = domid;
1725
1726 bind = &(domctl.u.bind_pt_irq);
1727 bind->irq_type = PT_IRQ_TYPE_MSI;
1728 bind->machine_irq = pirq;
1729 bind->u.msi.gvec = gvec;
1730 bind->u.msi.gflags = gflags;
1731
1732 rc = do_domctl(xch, &domctl);
1733 return rc;
1734 }
1735
1736 /* Pass-through: binds machine irq to guests irq */
xc_domain_bind_pt_irq_int(xc_interface * xch,uint32_t domid,uint32_t machine_irq,uint8_t irq_type,uint8_t bus,uint8_t device,uint8_t intx,uint8_t isa_irq,uint16_t spi)1737 static int xc_domain_bind_pt_irq_int(
1738 xc_interface *xch,
1739 uint32_t domid,
1740 uint32_t machine_irq,
1741 uint8_t irq_type,
1742 uint8_t bus,
1743 uint8_t device,
1744 uint8_t intx,
1745 uint8_t isa_irq,
1746 uint16_t spi)
1747 {
1748 int rc;
1749 struct xen_domctl_bind_pt_irq *bind;
1750 DECLARE_DOMCTL;
1751
1752 domctl.cmd = XEN_DOMCTL_bind_pt_irq;
1753 domctl.domain = domid;
1754
1755 bind = &(domctl.u.bind_pt_irq);
1756 bind->irq_type = irq_type;
1757 bind->machine_irq = machine_irq;
1758 switch ( irq_type )
1759 {
1760 case PT_IRQ_TYPE_PCI:
1761 case PT_IRQ_TYPE_MSI_TRANSLATE:
1762 bind->u.pci.bus = bus;
1763 bind->u.pci.device = device;
1764 bind->u.pci.intx = intx;
1765 break;
1766 case PT_IRQ_TYPE_ISA:
1767 bind->u.isa.isa_irq = isa_irq;
1768 break;
1769 case PT_IRQ_TYPE_SPI:
1770 bind->u.spi.spi = spi;
1771 break;
1772 default:
1773 errno = EINVAL;
1774 return -1;
1775 }
1776
1777 rc = do_domctl(xch, &domctl);
1778 return rc;
1779 }
1780
xc_domain_bind_pt_irq(xc_interface * xch,uint32_t domid,uint8_t machine_irq,uint8_t irq_type,uint8_t bus,uint8_t device,uint8_t intx,uint8_t isa_irq)1781 int xc_domain_bind_pt_irq(
1782 xc_interface *xch,
1783 uint32_t domid,
1784 uint8_t machine_irq,
1785 uint8_t irq_type,
1786 uint8_t bus,
1787 uint8_t device,
1788 uint8_t intx,
1789 uint8_t isa_irq)
1790 {
1791 return xc_domain_bind_pt_irq_int(xch, domid, machine_irq, irq_type,
1792 bus, device, intx, isa_irq, 0);
1793 }
1794
xc_domain_unbind_pt_irq_int(xc_interface * xch,uint32_t domid,uint32_t machine_irq,uint8_t irq_type,uint8_t bus,uint8_t device,uint8_t intx,uint8_t isa_irq,uint8_t spi)1795 static int xc_domain_unbind_pt_irq_int(
1796 xc_interface *xch,
1797 uint32_t domid,
1798 uint32_t machine_irq,
1799 uint8_t irq_type,
1800 uint8_t bus,
1801 uint8_t device,
1802 uint8_t intx,
1803 uint8_t isa_irq,
1804 uint8_t spi)
1805 {
1806 int rc;
1807 struct xen_domctl_bind_pt_irq *bind;
1808 DECLARE_DOMCTL;
1809
1810 domctl.cmd = XEN_DOMCTL_unbind_pt_irq;
1811 domctl.domain = domid;
1812
1813 bind = &(domctl.u.bind_pt_irq);
1814 bind->irq_type = irq_type;
1815 bind->machine_irq = machine_irq;
1816 switch ( irq_type )
1817 {
1818 case PT_IRQ_TYPE_PCI:
1819 case PT_IRQ_TYPE_MSI_TRANSLATE:
1820 bind->u.pci.bus = bus;
1821 bind->u.pci.device = device;
1822 bind->u.pci.intx = intx;
1823 break;
1824 case PT_IRQ_TYPE_ISA:
1825 bind->u.isa.isa_irq = isa_irq;
1826 break;
1827 case PT_IRQ_TYPE_SPI:
1828 bind->u.spi.spi = spi;
1829 break;
1830 default:
1831 errno = EINVAL;
1832 return -1;
1833 }
1834
1835 rc = do_domctl(xch, &domctl);
1836 return rc;
1837 }
1838
xc_domain_unbind_pt_irq(xc_interface * xch,uint32_t domid,uint8_t machine_irq,uint8_t irq_type,uint8_t bus,uint8_t device,uint8_t intx,uint8_t isa_irq)1839 int xc_domain_unbind_pt_irq(
1840 xc_interface *xch,
1841 uint32_t domid,
1842 uint8_t machine_irq,
1843 uint8_t irq_type,
1844 uint8_t bus,
1845 uint8_t device,
1846 uint8_t intx,
1847 uint8_t isa_irq)
1848 {
1849 return xc_domain_unbind_pt_irq_int(xch, domid, machine_irq, irq_type,
1850 bus, device, intx, isa_irq, 0);
1851 }
1852
xc_domain_bind_pt_pci_irq(xc_interface * xch,uint32_t domid,uint8_t machine_irq,uint8_t bus,uint8_t device,uint8_t intx)1853 int xc_domain_bind_pt_pci_irq(
1854 xc_interface *xch,
1855 uint32_t domid,
1856 uint8_t machine_irq,
1857 uint8_t bus,
1858 uint8_t device,
1859 uint8_t intx)
1860 {
1861
1862 return (xc_domain_bind_pt_irq(xch, domid, machine_irq,
1863 PT_IRQ_TYPE_PCI, bus, device, intx, 0));
1864 }
1865
xc_domain_bind_pt_isa_irq(xc_interface * xch,uint32_t domid,uint8_t machine_irq)1866 int xc_domain_bind_pt_isa_irq(
1867 xc_interface *xch,
1868 uint32_t domid,
1869 uint8_t machine_irq)
1870 {
1871
1872 return (xc_domain_bind_pt_irq(xch, domid, machine_irq,
1873 PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq));
1874 }
1875
xc_domain_bind_pt_spi_irq(xc_interface * xch,uint32_t domid,uint16_t vspi,uint16_t spi)1876 int xc_domain_bind_pt_spi_irq(
1877 xc_interface *xch,
1878 uint32_t domid,
1879 uint16_t vspi,
1880 uint16_t spi)
1881 {
1882 return (xc_domain_bind_pt_irq_int(xch, domid, vspi,
1883 PT_IRQ_TYPE_SPI, 0, 0, 0, 0, spi));
1884 }
1885
xc_domain_unbind_pt_spi_irq(xc_interface * xch,uint32_t domid,uint16_t vspi,uint16_t spi)1886 int xc_domain_unbind_pt_spi_irq(xc_interface *xch,
1887 uint32_t domid,
1888 uint16_t vspi,
1889 uint16_t spi)
1890 {
1891 return (xc_domain_unbind_pt_irq_int(xch, domid, vspi,
1892 PT_IRQ_TYPE_SPI, 0, 0, 0, 0, spi));
1893 }
1894
xc_unmap_domain_meminfo(xc_interface * xch,struct xc_domain_meminfo * minfo)1895 int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *minfo)
1896 {
1897 struct domain_info_context _di = { .guest_width = minfo->guest_width,
1898 .p2m_size = minfo->p2m_size};
1899 struct domain_info_context *dinfo = &_di;
1900
1901 free(minfo->pfn_type);
1902 if ( minfo->p2m_table )
1903 munmap(minfo->p2m_table, P2M_FL_ENTRIES * PAGE_SIZE);
1904 minfo->p2m_table = NULL;
1905
1906 return 0;
1907 }
1908
xc_map_domain_meminfo(xc_interface * xch,uint32_t domid,struct xc_domain_meminfo * minfo)1909 int xc_map_domain_meminfo(xc_interface *xch, uint32_t domid,
1910 struct xc_domain_meminfo *minfo)
1911 {
1912 struct domain_info_context _di;
1913 struct domain_info_context *dinfo = &_di;
1914
1915 xc_dominfo_t info;
1916 shared_info_any_t *live_shinfo;
1917 xen_capabilities_info_t xen_caps = "";
1918 int i;
1919
1920 /* Only be initialized once */
1921 if ( minfo->pfn_type || minfo->p2m_table )
1922 {
1923 errno = EINVAL;
1924 return -1;
1925 }
1926
1927 if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 )
1928 {
1929 PERROR("Could not get domain info");
1930 return -1;
1931 }
1932
1933 if ( xc_domain_get_guest_width(xch, domid, &minfo->guest_width) )
1934 {
1935 PERROR("Could not get domain address size");
1936 return -1;
1937 }
1938 _di.guest_width = minfo->guest_width;
1939
1940 /* Get page table levels (see get_platform_info() in xg_save_restore.h */
1941 if ( xc_version(xch, XENVER_capabilities, &xen_caps) )
1942 {
1943 PERROR("Could not get Xen capabilities (for page table levels)");
1944 return -1;
1945 }
1946 if ( strstr(xen_caps, "xen-3.0-x86_64") )
1947 /* Depends on whether it's a compat 32-on-64 guest */
1948 minfo->pt_levels = ( (minfo->guest_width == 8) ? 4 : 3 );
1949 else if ( strstr(xen_caps, "xen-3.0-x86_32p") )
1950 minfo->pt_levels = 3;
1951 else if ( strstr(xen_caps, "xen-3.0-x86_32") )
1952 minfo->pt_levels = 2;
1953 else
1954 {
1955 errno = EFAULT;
1956 return -1;
1957 }
1958
1959 /* We need the shared info page for mapping the P2M */
1960 live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ,
1961 info.shared_info_frame);
1962 if ( !live_shinfo )
1963 {
1964 PERROR("Could not map the shared info frame (MFN 0x%lx)",
1965 info.shared_info_frame);
1966 return -1;
1967 }
1968
1969 if ( xc_core_arch_map_p2m_writable(xch, minfo->guest_width, &info,
1970 live_shinfo, &minfo->p2m_table,
1971 &minfo->p2m_size) )
1972 {
1973 PERROR("Could not map the P2M table");
1974 munmap(live_shinfo, PAGE_SIZE);
1975 return -1;
1976 }
1977 munmap(live_shinfo, PAGE_SIZE);
1978 _di.p2m_size = minfo->p2m_size;
1979
1980 /* Make space and prepare for getting the PFN types */
1981 minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size);
1982 if ( !minfo->pfn_type )
1983 {
1984 PERROR("Could not allocate memory for the PFN types");
1985 goto failed;
1986 }
1987 for ( i = 0; i < minfo->p2m_size; i++ )
1988 minfo->pfn_type[i] = xc_pfn_to_mfn(i, minfo->p2m_table,
1989 minfo->guest_width);
1990
1991 /* Retrieve PFN types in batches */
1992 for ( i = 0; i < minfo->p2m_size ; i+=1024 )
1993 {
1994 int count = ((minfo->p2m_size - i ) > 1024 ) ?
1995 1024: (minfo->p2m_size - i);
1996
1997 if ( xc_get_pfn_type_batch(xch, domid, count, minfo->pfn_type + i) )
1998 {
1999 PERROR("Could not get %d-eth batch of PFN types", (i+1)/1024);
2000 goto failed;
2001 }
2002 }
2003
2004 return 0;
2005
2006 failed:
2007 if ( minfo->pfn_type )
2008 {
2009 free(minfo->pfn_type);
2010 minfo->pfn_type = NULL;
2011 }
2012 if ( minfo->p2m_table )
2013 {
2014 munmap(minfo->p2m_table, P2M_FL_ENTRIES * PAGE_SIZE);
2015 minfo->p2m_table = NULL;
2016 }
2017
2018 return -1;
2019 }
2020
xc_domain_memory_mapping(xc_interface * xch,uint32_t domid,unsigned long first_gfn,unsigned long first_mfn,unsigned long nr_mfns,uint32_t add_mapping)2021 int xc_domain_memory_mapping(
2022 xc_interface *xch,
2023 uint32_t domid,
2024 unsigned long first_gfn,
2025 unsigned long first_mfn,
2026 unsigned long nr_mfns,
2027 uint32_t add_mapping)
2028 {
2029 DECLARE_DOMCTL;
2030 xc_dominfo_t info;
2031 int ret = 0, rc;
2032 unsigned long done = 0, nr, max_batch_sz;
2033
2034 if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ||
2035 info.domid != domid )
2036 {
2037 PERROR("Could not get info for domain");
2038 return -EINVAL;
2039 }
2040 if ( !xc_core_arch_auto_translated_physmap(&info) )
2041 return 0;
2042
2043 if ( !nr_mfns )
2044 return 0;
2045
2046 domctl.cmd = XEN_DOMCTL_memory_mapping;
2047 domctl.domain = domid;
2048 domctl.u.memory_mapping.add_mapping = add_mapping;
2049 max_batch_sz = nr_mfns;
2050 do
2051 {
2052 nr = min_t(unsigned long, nr_mfns - done, max_batch_sz);
2053 domctl.u.memory_mapping.nr_mfns = nr;
2054 domctl.u.memory_mapping.first_gfn = first_gfn + done;
2055 domctl.u.memory_mapping.first_mfn = first_mfn + done;
2056 rc = do_domctl(xch, &domctl);
2057 if ( rc < 0 && errno == E2BIG )
2058 {
2059 if ( max_batch_sz <= 1 )
2060 break;
2061 max_batch_sz >>= 1;
2062 continue;
2063 }
2064 if ( rc > 0 )
2065 {
2066 done += rc;
2067 continue;
2068 }
2069 /* Save the first error... */
2070 if ( !ret )
2071 ret = rc;
2072 /* .. and ignore the rest of them when removing. */
2073 if ( rc && add_mapping != DPCI_REMOVE_MAPPING )
2074 break;
2075
2076 done += nr;
2077 } while ( done < nr_mfns );
2078
2079 /*
2080 * Undo what we have done unless unmapping, by unmapping the entire region.
2081 * Errors here are ignored.
2082 */
2083 if ( ret && add_mapping != DPCI_REMOVE_MAPPING )
2084 xc_domain_memory_mapping(xch, domid, first_gfn, first_mfn, nr_mfns,
2085 DPCI_REMOVE_MAPPING);
2086
2087 /* We might get E2BIG so many times that we never advance. */
2088 if ( !done && !ret )
2089 ret = -1;
2090
2091 return ret;
2092 }
2093
xc_domain_ioport_mapping(xc_interface * xch,uint32_t domid,uint32_t first_gport,uint32_t first_mport,uint32_t nr_ports,uint32_t add_mapping)2094 int xc_domain_ioport_mapping(
2095 xc_interface *xch,
2096 uint32_t domid,
2097 uint32_t first_gport,
2098 uint32_t first_mport,
2099 uint32_t nr_ports,
2100 uint32_t add_mapping)
2101 {
2102 DECLARE_DOMCTL;
2103
2104 domctl.cmd = XEN_DOMCTL_ioport_mapping;
2105 domctl.domain = domid;
2106 domctl.u.ioport_mapping.first_gport = first_gport;
2107 domctl.u.ioport_mapping.first_mport = first_mport;
2108 domctl.u.ioport_mapping.nr_ports = nr_ports;
2109 domctl.u.ioport_mapping.add_mapping = add_mapping;
2110
2111 return do_domctl(xch, &domctl);
2112 }
2113
xc_domain_set_target(xc_interface * xch,uint32_t domid,uint32_t target)2114 int xc_domain_set_target(
2115 xc_interface *xch,
2116 uint32_t domid,
2117 uint32_t target)
2118 {
2119 DECLARE_DOMCTL;
2120
2121 domctl.cmd = XEN_DOMCTL_set_target;
2122 domctl.domain = domid;
2123 domctl.u.set_target.target = target;
2124
2125 return do_domctl(xch, &domctl);
2126 }
2127
xc_domain_subscribe_for_suspend(xc_interface * xch,uint32_t dom,evtchn_port_t port)2128 int xc_domain_subscribe_for_suspend(
2129 xc_interface *xch, uint32_t dom, evtchn_port_t port)
2130 {
2131 DECLARE_DOMCTL;
2132
2133 domctl.cmd = XEN_DOMCTL_subscribe;
2134 domctl.domain = dom;
2135 domctl.u.subscribe.port = port;
2136
2137 return do_domctl(xch, &domctl);
2138 }
2139
xc_domain_debug_control(xc_interface * xc,uint32_t domid,uint32_t sop,uint32_t vcpu)2140 int xc_domain_debug_control(xc_interface *xc, uint32_t domid, uint32_t sop, uint32_t vcpu)
2141 {
2142 DECLARE_DOMCTL;
2143
2144 memset(&domctl, 0, sizeof(domctl));
2145 domctl.domain = domid;
2146 domctl.cmd = XEN_DOMCTL_debug_op;
2147 domctl.u.debug_op.op = sop;
2148 domctl.u.debug_op.vcpu = vcpu;
2149
2150 return do_domctl(xc, &domctl);
2151 }
2152
xc_domain_p2m_audit(xc_interface * xch,uint32_t domid,uint64_t * orphans,uint64_t * m2p_bad,uint64_t * p2m_bad)2153 int xc_domain_p2m_audit(xc_interface *xch,
2154 uint32_t domid,
2155 uint64_t *orphans,
2156 uint64_t *m2p_bad,
2157 uint64_t *p2m_bad)
2158 {
2159 DECLARE_DOMCTL;
2160 int rc;
2161
2162 domctl.cmd = XEN_DOMCTL_audit_p2m;
2163 domctl.domain = domid;
2164 rc = do_domctl(xch, &domctl);
2165
2166 *orphans = domctl.u.audit_p2m.orphans;
2167 *m2p_bad = domctl.u.audit_p2m.m2p_bad;
2168 *p2m_bad = domctl.u.audit_p2m.p2m_bad;
2169
2170 return rc;
2171 }
2172
xc_domain_set_access_required(xc_interface * xch,uint32_t domid,unsigned int required)2173 int xc_domain_set_access_required(xc_interface *xch,
2174 uint32_t domid,
2175 unsigned int required)
2176 {
2177 DECLARE_DOMCTL;
2178
2179 domctl.cmd = XEN_DOMCTL_set_access_required;
2180 domctl.domain = domid;
2181 domctl.u.access_required.access_required = required;
2182 return do_domctl(xch, &domctl);
2183 }
2184
xc_domain_set_virq_handler(xc_interface * xch,uint32_t domid,int virq)2185 int xc_domain_set_virq_handler(xc_interface *xch, uint32_t domid, int virq)
2186 {
2187 DECLARE_DOMCTL;
2188
2189 domctl.cmd = XEN_DOMCTL_set_virq_handler;
2190 domctl.domain = domid;
2191 domctl.u.set_virq_handler.virq = virq;
2192 return do_domctl(xch, &domctl);
2193 }
2194
2195 /* Plumbing Xen with vNUMA topology */
xc_domain_setvnuma(xc_interface * xch,uint32_t domid,uint32_t nr_vnodes,uint32_t nr_vmemranges,uint32_t nr_vcpus,xen_vmemrange_t * vmemrange,unsigned int * vdistance,unsigned int * vcpu_to_vnode,unsigned int * vnode_to_pnode)2196 int xc_domain_setvnuma(xc_interface *xch,
2197 uint32_t domid,
2198 uint32_t nr_vnodes,
2199 uint32_t nr_vmemranges,
2200 uint32_t nr_vcpus,
2201 xen_vmemrange_t *vmemrange,
2202 unsigned int *vdistance,
2203 unsigned int *vcpu_to_vnode,
2204 unsigned int *vnode_to_pnode)
2205 {
2206 int rc;
2207 DECLARE_DOMCTL;
2208 DECLARE_HYPERCALL_BOUNCE(vmemrange, sizeof(*vmemrange) * nr_vmemranges,
2209 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
2210 DECLARE_HYPERCALL_BOUNCE(vdistance, sizeof(*vdistance) *
2211 nr_vnodes * nr_vnodes,
2212 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
2213 DECLARE_HYPERCALL_BOUNCE(vcpu_to_vnode, sizeof(*vcpu_to_vnode) * nr_vcpus,
2214 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
2215 DECLARE_HYPERCALL_BOUNCE(vnode_to_pnode, sizeof(*vnode_to_pnode) *
2216 nr_vnodes,
2217 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
2218 errno = EINVAL;
2219
2220 if ( nr_vnodes == 0 || nr_vmemranges == 0 || nr_vcpus == 0 )
2221 return -1;
2222
2223 if ( !vdistance || !vcpu_to_vnode || !vmemrange || !vnode_to_pnode )
2224 {
2225 PERROR("%s: Cant set vnuma without initializing topology", __func__);
2226 return -1;
2227 }
2228
2229 if ( xc_hypercall_bounce_pre(xch, vmemrange) ||
2230 xc_hypercall_bounce_pre(xch, vdistance) ||
2231 xc_hypercall_bounce_pre(xch, vcpu_to_vnode) ||
2232 xc_hypercall_bounce_pre(xch, vnode_to_pnode) )
2233 {
2234 rc = -1;
2235 goto vnumaset_fail;
2236
2237 }
2238
2239 set_xen_guest_handle(domctl.u.vnuma.vmemrange, vmemrange);
2240 set_xen_guest_handle(domctl.u.vnuma.vdistance, vdistance);
2241 set_xen_guest_handle(domctl.u.vnuma.vcpu_to_vnode, vcpu_to_vnode);
2242 set_xen_guest_handle(domctl.u.vnuma.vnode_to_pnode, vnode_to_pnode);
2243
2244 domctl.cmd = XEN_DOMCTL_setvnumainfo;
2245 domctl.domain = domid;
2246 domctl.u.vnuma.nr_vnodes = nr_vnodes;
2247 domctl.u.vnuma.nr_vmemranges = nr_vmemranges;
2248 domctl.u.vnuma.nr_vcpus = nr_vcpus;
2249 domctl.u.vnuma.pad = 0;
2250
2251 rc = do_domctl(xch, &domctl);
2252
2253 vnumaset_fail:
2254 xc_hypercall_bounce_post(xch, vmemrange);
2255 xc_hypercall_bounce_post(xch, vdistance);
2256 xc_hypercall_bounce_post(xch, vcpu_to_vnode);
2257 xc_hypercall_bounce_post(xch, vnode_to_pnode);
2258
2259 return rc;
2260 }
2261
xc_domain_getvnuma(xc_interface * xch,uint32_t domid,uint32_t * nr_vnodes,uint32_t * nr_vmemranges,uint32_t * nr_vcpus,xen_vmemrange_t * vmemrange,unsigned int * vdistance,unsigned int * vcpu_to_vnode)2262 int xc_domain_getvnuma(xc_interface *xch,
2263 uint32_t domid,
2264 uint32_t *nr_vnodes,
2265 uint32_t *nr_vmemranges,
2266 uint32_t *nr_vcpus,
2267 xen_vmemrange_t *vmemrange,
2268 unsigned int *vdistance,
2269 unsigned int *vcpu_to_vnode)
2270 {
2271 int rc;
2272 DECLARE_HYPERCALL_BOUNCE(vmemrange, sizeof(*vmemrange) * *nr_vmemranges,
2273 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
2274 DECLARE_HYPERCALL_BOUNCE(vdistance, sizeof(*vdistance) *
2275 *nr_vnodes * *nr_vnodes,
2276 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
2277 DECLARE_HYPERCALL_BOUNCE(vcpu_to_vnode, sizeof(*vcpu_to_vnode) * *nr_vcpus,
2278 XC_HYPERCALL_BUFFER_BOUNCE_OUT);
2279
2280 struct xen_vnuma_topology_info vnuma_topo;
2281
2282 if ( xc_hypercall_bounce_pre(xch, vmemrange) ||
2283 xc_hypercall_bounce_pre(xch, vdistance) ||
2284 xc_hypercall_bounce_pre(xch, vcpu_to_vnode) )
2285 {
2286 rc = -1;
2287 errno = ENOMEM;
2288 goto vnumaget_fail;
2289 }
2290
2291 set_xen_guest_handle(vnuma_topo.vmemrange.h, vmemrange);
2292 set_xen_guest_handle(vnuma_topo.vdistance.h, vdistance);
2293 set_xen_guest_handle(vnuma_topo.vcpu_to_vnode.h, vcpu_to_vnode);
2294
2295 vnuma_topo.nr_vnodes = *nr_vnodes;
2296 vnuma_topo.nr_vcpus = *nr_vcpus;
2297 vnuma_topo.nr_vmemranges = *nr_vmemranges;
2298 vnuma_topo.domid = domid;
2299 vnuma_topo.pad = 0;
2300
2301 rc = do_memory_op(xch, XENMEM_get_vnumainfo, &vnuma_topo,
2302 sizeof(vnuma_topo));
2303
2304 *nr_vnodes = vnuma_topo.nr_vnodes;
2305 *nr_vcpus = vnuma_topo.nr_vcpus;
2306 *nr_vmemranges = vnuma_topo.nr_vmemranges;
2307
2308 vnumaget_fail:
2309 xc_hypercall_bounce_post(xch, vmemrange);
2310 xc_hypercall_bounce_post(xch, vdistance);
2311 xc_hypercall_bounce_post(xch, vcpu_to_vnode);
2312
2313 return rc;
2314 }
2315
xc_domain_soft_reset(xc_interface * xch,uint32_t domid)2316 int xc_domain_soft_reset(xc_interface *xch,
2317 uint32_t domid)
2318 {
2319 DECLARE_DOMCTL;
2320 domctl.cmd = XEN_DOMCTL_soft_reset;
2321 domctl.domain = domid;
2322 return do_domctl(xch, &domctl);
2323 }
2324 /*
2325 * Local variables:
2326 * mode: C
2327 * c-file-style: "BSD"
2328 * c-basic-offset: 4
2329 * tab-width: 4
2330 * indent-tabs-mode: nil
2331 * End:
2332 */
2333