1 /******************************************************************************
2 * domctl.c
3 *
4 * Domain management operations. For use by node control stack.
5 *
6 * Copyright (c) 2002-2006, K A Fraser
7 */
8
9 #include <xen/types.h>
10 #include <xen/lib.h>
11 #include <xen/llc-coloring.h>
12 #include <xen/err.h>
13 #include <xen/mm.h>
14 #include <xen/sched.h>
15 #include <xen/domain.h>
16 #include <xen/event.h>
17 #include <xen/grant_table.h>
18 #include <xen/domain_page.h>
19 #include <xen/trace.h>
20 #include <xen/console.h>
21 #include <xen/iocap.h>
22 #include <xen/rcupdate.h>
23 #include <xen/guest_access.h>
24 #include <xen/bitmap.h>
25 #include <xen/paging.h>
26 #include <xen/hypercall.h>
27 #include <xen/vm_event.h>
28 #include <xen/monitor.h>
29 #include <xen/xvmalloc.h>
30
31 #include <asm/current.h>
32 #include <asm/irq.h>
33 #include <asm/page.h>
34 #include <asm/p2m.h>
35 #include <public/domctl.h>
36 #include <xsm/xsm.h>
37
38 static DEFINE_SPINLOCK(domctl_lock);
39
nodemask_to_xenctl_bitmap(struct xenctl_bitmap * xenctl_nodemap,const nodemask_t * nodemask)40 static int nodemask_to_xenctl_bitmap(struct xenctl_bitmap *xenctl_nodemap,
41 const nodemask_t *nodemask)
42 {
43 return bitmap_to_xenctl_bitmap(xenctl_nodemap, nodemask_bits(nodemask),
44 MAX_NUMNODES);
45 }
46
xenctl_bitmap_to_nodemask(nodemask_t * nodemask,const struct xenctl_bitmap * xenctl_nodemap)47 static int xenctl_bitmap_to_nodemask(nodemask_t *nodemask,
48 const struct xenctl_bitmap *xenctl_nodemap)
49 {
50 return xenctl_bitmap_to_bitmap(nodemask_bits(nodemask), xenctl_nodemap,
51 MAX_NUMNODES);
52 }
53
is_free_domid(domid_t dom)54 static inline int is_free_domid(domid_t dom)
55 {
56 struct domain *d;
57
58 if ( dom >= DOMID_FIRST_RESERVED )
59 return 0;
60
61 if ( (d = rcu_lock_domain_by_id(dom)) == NULL )
62 return 1;
63
64 rcu_unlock_domain(d);
65 return 0;
66 }
67
getdomaininfo(struct domain * d,struct xen_domctl_getdomaininfo * info)68 void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
69 {
70 struct vcpu *v;
71 u64 cpu_time = 0;
72 int flags = XEN_DOMINF_blocked;
73 struct vcpu_runstate_info runstate;
74
75 memset(info, 0, sizeof(*info));
76
77 info->domain = d->domain_id;
78 info->max_vcpu_id = XEN_INVALID_MAX_VCPU_ID;
79
80 /*
81 * - domain is marked as blocked only if all its vcpus are blocked
82 * - domain is marked as running if any of its vcpus is running
83 */
84 for_each_vcpu ( d, v )
85 {
86 vcpu_runstate_get(v, &runstate);
87 cpu_time += runstate.time[RUNSTATE_running];
88 info->max_vcpu_id = v->vcpu_id;
89 if ( !(v->pause_flags & VPF_down) )
90 {
91 if ( !(v->pause_flags & VPF_blocked) )
92 flags &= ~XEN_DOMINF_blocked;
93 if ( v->is_running )
94 flags |= XEN_DOMINF_running;
95 info->nr_online_vcpus++;
96 }
97 }
98
99 info->cpu_time = cpu_time;
100
101 info->flags = (info->nr_online_vcpus ? flags : 0) |
102 ((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying : 0) |
103 (d->is_shut_down ? XEN_DOMINF_shutdown : 0) |
104 (d->controller_pause_count > 0 ? XEN_DOMINF_paused : 0) |
105 (d->debugger_attached ? XEN_DOMINF_debugged : 0) |
106 (is_xenstore_domain(d) ? XEN_DOMINF_xs_domain : 0) |
107 (is_hvm_domain(d) ? XEN_DOMINF_hvm_guest : 0) |
108 d->shutdown_code << XEN_DOMINF_shutdownshift;
109
110 xsm_security_domaininfo(d, info);
111
112 info->tot_pages = domain_tot_pages(d);
113 info->max_pages = d->max_pages;
114 info->outstanding_pages = d->outstanding_pages;
115 #ifdef CONFIG_MEM_SHARING
116 info->shr_pages = atomic_read(&d->shr_pages);
117 #endif
118 #ifdef CONFIG_MEM_PAGING
119 info->paged_pages = atomic_read(&d->paged_pages);
120 #endif
121 info->shared_info_frame =
122 gfn_x(mfn_to_gfn(d, _mfn(virt_to_mfn(d->shared_info))));
123 BUG_ON(SHARED_M2P(info->shared_info_frame));
124
125 info->cpupool = cpupool_get_id(d);
126
127 memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
128
129 arch_get_domain_info(d, info);
130 }
131
domctl_lock_acquire(void)132 bool domctl_lock_acquire(void)
133 {
134 /*
135 * Caller may try to pause its own VCPUs. We must prevent deadlock
136 * against other non-domctl routines which try to do the same.
137 */
138 if ( !spin_trylock(¤t->domain->hypercall_deadlock_mutex) )
139 return 0;
140
141 /*
142 * Trylock here is paranoia if we have multiple privileged domains. Then
143 * we could have one domain trying to pause another which is spinning
144 * on domctl_lock -- results in deadlock.
145 */
146 if ( spin_trylock(&domctl_lock) )
147 return 1;
148
149 spin_unlock(¤t->domain->hypercall_deadlock_mutex);
150 return 0;
151 }
152
domctl_lock_release(void)153 void domctl_lock_release(void)
154 {
155 spin_unlock(&domctl_lock);
156 spin_unlock(¤t->domain->hypercall_deadlock_mutex);
157 }
158
vnuma_destroy(struct vnuma_info * vnuma)159 void vnuma_destroy(struct vnuma_info *vnuma)
160 {
161 if ( vnuma )
162 {
163 xfree(vnuma->vmemrange);
164 xfree(vnuma->vcpu_to_vnode);
165 xvfree(vnuma->vdistance);
166 xfree(vnuma->vnode_to_pnode);
167 xfree(vnuma);
168 }
169 }
170
171 /*
172 * Allocates memory for vNUMA, **vnuma should be NULL.
173 * Caller has to make sure that domain has max_pages
174 * and number of vcpus set for domain.
175 * Verifies that single allocation does not exceed
176 * PAGE_SIZE.
177 */
vnuma_alloc(unsigned int nr_vnodes,unsigned int nr_ranges,unsigned int nr_vcpus)178 static struct vnuma_info *vnuma_alloc(unsigned int nr_vnodes,
179 unsigned int nr_ranges,
180 unsigned int nr_vcpus)
181 {
182
183 struct vnuma_info *vnuma;
184
185 /*
186 * Check if any of the allocations are bigger than PAGE_SIZE.
187 * See XSA-77.
188 */
189 if ( nr_vnodes == 0 ||
190 nr_vnodes > (PAGE_SIZE / sizeof(*vnuma->vdistance) / nr_vnodes) ||
191 nr_ranges > (PAGE_SIZE / sizeof(*vnuma->vmemrange)) )
192 return ERR_PTR(-EINVAL);
193
194 /*
195 * If allocations become larger then PAGE_SIZE, these allocations
196 * should be split into PAGE_SIZE allocations due to XSA-77.
197 */
198 vnuma = xmalloc(struct vnuma_info);
199 if ( !vnuma )
200 return ERR_PTR(-ENOMEM);
201
202 vnuma->vdistance = xvmalloc_array(unsigned int, nr_vnodes, nr_vnodes);
203 vnuma->vcpu_to_vnode = xmalloc_array(unsigned int, nr_vcpus);
204 vnuma->vnode_to_pnode = xmalloc_array(nodeid_t, nr_vnodes);
205 vnuma->vmemrange = xmalloc_array(xen_vmemrange_t, nr_ranges);
206
207 if ( vnuma->vdistance == NULL || vnuma->vmemrange == NULL ||
208 vnuma->vcpu_to_vnode == NULL || vnuma->vnode_to_pnode == NULL )
209 {
210 vnuma_destroy(vnuma);
211 return ERR_PTR(-ENOMEM);
212 }
213
214 return vnuma;
215 }
216
217 /*
218 * Construct vNUMA topology form uinfo.
219 */
vnuma_init(const struct xen_domctl_vnuma * uinfo,const struct domain * d)220 static struct vnuma_info *vnuma_init(const struct xen_domctl_vnuma *uinfo,
221 const struct domain *d)
222 {
223 unsigned int i, nr_vnodes;
224 int ret = -EINVAL;
225 struct vnuma_info *info;
226
227 nr_vnodes = uinfo->nr_vnodes;
228
229 if ( uinfo->nr_vcpus != d->max_vcpus || uinfo->pad != 0 )
230 return ERR_PTR(ret);
231
232 info = vnuma_alloc(nr_vnodes, uinfo->nr_vmemranges, d->max_vcpus);
233 if ( IS_ERR(info) )
234 return info;
235
236 ret = -EFAULT;
237
238 if ( copy_from_guest(info->vdistance, uinfo->vdistance,
239 nr_vnodes * nr_vnodes) )
240 goto vnuma_fail;
241
242 if ( copy_from_guest(info->vmemrange, uinfo->vmemrange,
243 uinfo->nr_vmemranges) )
244 goto vnuma_fail;
245
246 if ( copy_from_guest(info->vcpu_to_vnode, uinfo->vcpu_to_vnode,
247 d->max_vcpus) )
248 goto vnuma_fail;
249
250 ret = -E2BIG;
251 for ( i = 0; i < d->max_vcpus; ++i )
252 if ( info->vcpu_to_vnode[i] >= nr_vnodes )
253 goto vnuma_fail;
254
255 for ( i = 0; i < nr_vnodes; ++i )
256 {
257 unsigned int pnode;
258
259 ret = -EFAULT;
260 if ( copy_from_guest_offset(&pnode, uinfo->vnode_to_pnode, i, 1) )
261 goto vnuma_fail;
262 ret = -E2BIG;
263 if ( pnode >= MAX_NUMNODES )
264 goto vnuma_fail;
265 info->vnode_to_pnode[i] = pnode;
266 }
267
268 info->nr_vnodes = nr_vnodes;
269 info->nr_vmemranges = uinfo->nr_vmemranges;
270
271 /* Check that vmemranges flags are zero. */
272 ret = -EINVAL;
273 for ( i = 0; i < info->nr_vmemranges; i++ )
274 if ( info->vmemrange[i].flags != 0 )
275 goto vnuma_fail;
276
277 return info;
278
279 vnuma_fail:
280 vnuma_destroy(info);
281 return ERR_PTR(ret);
282 }
283
is_stable_domctl(uint32_t cmd)284 static bool is_stable_domctl(uint32_t cmd)
285 {
286 return cmd == XEN_DOMCTL_get_domain_state;
287 }
288
do_domctl(XEN_GUEST_HANDLE_PARAM (xen_domctl_t)u_domctl)289 long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
290 {
291 long ret = 0;
292 bool copyback = false;
293 struct xen_domctl curop, *op = &curop;
294 struct domain *d;
295
296 if ( copy_from_guest(op, u_domctl, 1) )
297 return -EFAULT;
298
299 if ( op->interface_version !=
300 (is_stable_domctl(op->cmd) ? 0 : XEN_DOMCTL_INTERFACE_VERSION) )
301 return -EACCES;
302
303 switch ( op->cmd )
304 {
305 case XEN_DOMCTL_createdomain:
306 d = NULL;
307 break;
308
309 case XEN_DOMCTL_assign_device:
310 case XEN_DOMCTL_deassign_device:
311 if ( op->domain == DOMID_IO )
312 {
313 d = dom_io;
314 break;
315 }
316 else if ( op->domain == DOMID_INVALID )
317 return -ESRCH;
318 fallthrough;
319 case XEN_DOMCTL_test_assign_device:
320 case XEN_DOMCTL_vm_event_op:
321 case XEN_DOMCTL_get_domain_state:
322 if ( op->domain == DOMID_INVALID )
323 {
324 d = NULL;
325 break;
326 }
327 fallthrough;
328 default:
329 d = rcu_lock_domain_by_id(op->domain);
330 if ( !d )
331 return -ESRCH;
332 break;
333 }
334
335 ret = xsm_domctl(XSM_OTHER, d, op->cmd,
336 /* SSIDRef only applicable for cmd == createdomain */
337 op->u.createdomain.ssidref);
338 if ( ret )
339 goto domctl_out_unlock_domonly;
340
341 if ( !domctl_lock_acquire() )
342 {
343 if ( d && d != dom_io )
344 rcu_unlock_domain(d);
345 return hypercall_create_continuation(
346 __HYPERVISOR_domctl, "h", u_domctl);
347 }
348
349 switch ( op->cmd )
350 {
351
352 case XEN_DOMCTL_setvcpucontext:
353 {
354 vcpu_guest_context_u c = { .nat = NULL };
355 unsigned int vcpu = op->u.vcpucontext.vcpu;
356 struct vcpu *v;
357
358 ret = -EINVAL;
359 if ( (d == current->domain) || /* no domain_pause() */
360 (vcpu >= d->max_vcpus) || ((v = d->vcpu[vcpu]) == NULL) )
361 break;
362
363 if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
364 {
365 ret = vcpu_reset(v);
366 if ( ret == -ERESTART )
367 ret = hypercall_create_continuation(
368 __HYPERVISOR_domctl, "h", u_domctl);
369 break;
370 }
371
372 #ifdef CONFIG_COMPAT
373 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
374 < sizeof(struct compat_vcpu_guest_context));
375 #endif
376 ret = -ENOMEM;
377 if ( (c.nat = alloc_vcpu_guest_context()) == NULL )
378 break;
379
380 #ifdef CONFIG_COMPAT
381 if ( !is_pv_32bit_domain(d) )
382 ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
383 else
384 ret = copy_from_guest(c.cmp,
385 guest_handle_cast(op->u.vcpucontext.ctxt,
386 void), 1);
387 #else
388 ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
389 #endif
390 ret = ret ? -EFAULT : 0;
391
392 if ( ret == 0 )
393 {
394 domain_pause(d);
395 ret = arch_set_info_guest(v, c);
396 domain_unpause(d);
397
398 if ( ret == -ERESTART )
399 ret = hypercall_create_continuation(
400 __HYPERVISOR_domctl, "h", u_domctl);
401 }
402
403 free_vcpu_guest_context(c.nat);
404 break;
405 }
406
407 case XEN_DOMCTL_pausedomain:
408 ret = -EINVAL;
409 if ( d != current->domain )
410 ret = domain_pause_by_systemcontroller(d);
411 break;
412
413 case XEN_DOMCTL_unpausedomain:
414 ret = domain_unpause_by_systemcontroller(d);
415 break;
416
417 case XEN_DOMCTL_resumedomain:
418 if ( d == current->domain ) /* no domain_pause() */
419 ret = -EINVAL;
420 else
421 domain_resume(d);
422 break;
423
424 case XEN_DOMCTL_createdomain:
425 {
426 domid_t dom;
427 static domid_t rover = 0;
428
429 dom = op->domain;
430 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
431 {
432 ret = -EEXIST;
433 if ( !is_free_domid(dom) )
434 break;
435 }
436 else
437 {
438 for ( dom = rover + 1; dom != rover; dom++ )
439 {
440 if ( dom == DOMID_FIRST_RESERVED )
441 dom = 1;
442 if ( is_free_domid(dom) )
443 break;
444 }
445
446 ret = -ENOMEM;
447 if ( dom == rover )
448 break;
449
450 rover = dom;
451 }
452
453 d = domain_create(dom, &op->u.createdomain, false);
454 if ( IS_ERR(d) )
455 {
456 ret = PTR_ERR(d);
457 d = NULL;
458 break;
459 }
460
461 ret = 0;
462 op->domain = d->domain_id;
463 copyback = 1;
464 d = NULL;
465 break;
466 }
467
468 case XEN_DOMCTL_max_vcpus:
469 {
470 unsigned int i, max = op->u.max_vcpus.max;
471
472 ret = -EINVAL;
473 if ( (d == current->domain) || /* no domain_pause() */
474 (max != d->max_vcpus) ) /* max_vcpus set up in createdomain */
475 break;
476
477 /* Needed, for example, to ensure writable p.t. state is synced. */
478 domain_pause(d);
479
480 ret = -ENOMEM;
481
482 for ( i = 0; i < max; i++ )
483 {
484 if ( d->vcpu[i] != NULL )
485 continue;
486
487 if ( vcpu_create(d, i) == NULL )
488 goto maxvcpu_out;
489 }
490
491 domain_update_node_affinity(d);
492 ret = 0;
493
494 maxvcpu_out:
495 domain_unpause(d);
496 break;
497 }
498
499 case XEN_DOMCTL_soft_reset:
500 case XEN_DOMCTL_soft_reset_cont:
501 if ( d == current->domain ) /* no domain_pause() */
502 {
503 ret = -EINVAL;
504 break;
505 }
506 ret = domain_soft_reset(d, op->cmd == XEN_DOMCTL_soft_reset_cont);
507 if ( ret == -ERESTART )
508 {
509 op->cmd = XEN_DOMCTL_soft_reset_cont;
510 if ( !__copy_field_to_guest(u_domctl, op, cmd) )
511 ret = hypercall_create_continuation(__HYPERVISOR_domctl,
512 "h", u_domctl);
513 else
514 ret = -EFAULT;
515 }
516 break;
517
518 case XEN_DOMCTL_destroydomain:
519 ret = domain_kill(d);
520 if ( ret == -ERESTART )
521 ret = hypercall_create_continuation(
522 __HYPERVISOR_domctl, "h", u_domctl);
523 break;
524
525 case XEN_DOMCTL_setnodeaffinity:
526 {
527 nodemask_t new_affinity;
528
529 ret = xenctl_bitmap_to_nodemask(&new_affinity,
530 &op->u.nodeaffinity.nodemap);
531 if ( !ret )
532 ret = domain_set_node_affinity(d, &new_affinity);
533 break;
534 }
535
536 case XEN_DOMCTL_getnodeaffinity:
537 ret = nodemask_to_xenctl_bitmap(&op->u.nodeaffinity.nodemap,
538 &d->node_affinity);
539 break;
540
541 case XEN_DOMCTL_setvcpuaffinity:
542 case XEN_DOMCTL_getvcpuaffinity:
543 ret = vcpu_affinity_domctl(d, op->cmd, &op->u.vcpuaffinity);
544 break;
545
546 case XEN_DOMCTL_scheduler_op:
547 ret = sched_adjust(d, &op->u.scheduler_op);
548 copyback = 1;
549 break;
550
551 case XEN_DOMCTL_getdomaininfo:
552 ret = xsm_getdomaininfo(XSM_XS_PRIV, d);
553 if ( ret )
554 break;
555
556 getdomaininfo(d, &op->u.getdomaininfo);
557
558 op->domain = op->u.getdomaininfo.domain;
559 copyback = 1;
560 break;
561
562 case XEN_DOMCTL_getvcpucontext:
563 {
564 vcpu_guest_context_u c = { .nat = NULL };
565 struct vcpu *v;
566
567 ret = -EINVAL;
568 if ( op->u.vcpucontext.vcpu >= d->max_vcpus ||
569 (v = d->vcpu[op->u.vcpucontext.vcpu]) == NULL ||
570 v == current ) /* no vcpu_pause() */
571 goto getvcpucontext_out;
572
573 ret = -ENODATA;
574 if ( !v->is_initialised )
575 goto getvcpucontext_out;
576
577 #ifdef CONFIG_COMPAT
578 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
579 < sizeof(struct compat_vcpu_guest_context));
580 #endif
581 ret = -ENOMEM;
582 if ( (c.nat = xzalloc(struct vcpu_guest_context)) == NULL )
583 goto getvcpucontext_out;
584
585 vcpu_pause(v);
586
587 arch_get_info_guest(v, c);
588 ret = 0;
589
590 vcpu_unpause(v);
591
592 #ifdef CONFIG_COMPAT
593 if ( !is_pv_32bit_domain(d) )
594 ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
595 else
596 ret = copy_to_guest(guest_handle_cast(op->u.vcpucontext.ctxt,
597 void), c.cmp, 1);
598 #else
599 ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
600 #endif
601
602 if ( ret )
603 ret = -EFAULT;
604 copyback = 1;
605
606 getvcpucontext_out:
607 xfree(c.nat);
608 break;
609 }
610
611 case XEN_DOMCTL_getvcpuinfo:
612 {
613 struct vcpu *v;
614 struct vcpu_runstate_info runstate;
615
616 ret = -EINVAL;
617 if ( op->u.getvcpuinfo.vcpu >= d->max_vcpus )
618 break;
619
620 ret = -ESRCH;
621 if ( (v = d->vcpu[op->u.getvcpuinfo.vcpu]) == NULL )
622 break;
623
624 vcpu_runstate_get(v, &runstate);
625
626 op->u.getvcpuinfo.online = !(v->pause_flags & VPF_down);
627 op->u.getvcpuinfo.blocked = !!(v->pause_flags & VPF_blocked);
628 op->u.getvcpuinfo.running = v->is_running;
629 op->u.getvcpuinfo.cpu_time = runstate.time[RUNSTATE_running];
630 op->u.getvcpuinfo.cpu = v->processor;
631 ret = 0;
632 copyback = 1;
633 break;
634 }
635
636 case XEN_DOMCTL_max_mem:
637 {
638 uint64_t new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT - 10);
639
640 nrspin_lock(&d->page_alloc_lock);
641 /*
642 * NB. We removed a check that new_max >= current tot_pages; this means
643 * that the domain will now be allowed to "ratchet" down to new_max. In
644 * the meantime, while tot > max, all new allocations are disallowed.
645 */
646 d->max_pages = min(new_max, (uint64_t)(typeof(d->max_pages))-1);
647 nrspin_unlock(&d->page_alloc_lock);
648 break;
649 }
650
651 case XEN_DOMCTL_setdomainhandle:
652 memcpy(d->handle, op->u.setdomainhandle.handle,
653 sizeof(xen_domain_handle_t));
654 break;
655
656 case XEN_DOMCTL_setdebugging:
657 if ( unlikely(d == current->domain) ) /* no domain_pause() */
658 ret = -EINVAL;
659 else
660 {
661 domain_pause(d);
662 d->debugger_attached = !!op->u.setdebugging.enable;
663 domain_unpause(d); /* causes guest to latch new status */
664 }
665 break;
666
667 #ifdef CONFIG_HAS_PIRQ
668 case XEN_DOMCTL_irq_permission:
669 {
670 unsigned int pirq = op->u.irq_permission.pirq, irq;
671 int allow = op->u.irq_permission.allow_access;
672
673 if ( pirq >= current->domain->nr_pirqs )
674 {
675 ret = -EINVAL;
676 break;
677 }
678 irq = pirq_access_permitted(current->domain, pirq);
679 if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) )
680 ret = -EPERM;
681 else if ( allow )
682 ret = irq_permit_access(d, irq);
683 else
684 ret = irq_deny_access(d, irq);
685 break;
686 }
687 #endif
688
689 case XEN_DOMCTL_iomem_permission:
690 {
691 unsigned long mfn = op->u.iomem_permission.first_mfn;
692 unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
693 int allow = op->u.iomem_permission.allow_access;
694
695 ret = -EINVAL;
696 if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
697 break;
698
699 if ( !iomem_access_permitted(current->domain,
700 mfn, mfn + nr_mfns - 1) ||
701 xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) )
702 ret = -EPERM;
703 else if ( allow )
704 ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
705 else
706 ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
707 break;
708 }
709
710 case XEN_DOMCTL_memory_mapping:
711 {
712 unsigned long gfn = op->u.memory_mapping.first_gfn;
713 unsigned long mfn = op->u.memory_mapping.first_mfn;
714 unsigned long nr_mfns = op->u.memory_mapping.nr_mfns;
715 unsigned long mfn_end = mfn + nr_mfns - 1;
716 int add = op->u.memory_mapping.add_mapping;
717
718 ret = -EINVAL;
719 if ( mfn_end < mfn || /* wrap? */
720 ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) ||
721 (gfn + nr_mfns - 1) < gfn ) /* wrap? */
722 break;
723
724 #ifndef CONFIG_X86 /* XXX ARM!? */
725 ret = -E2BIG;
726 /* Must break hypercall up as this could take a while. */
727 if ( nr_mfns > 64 )
728 break;
729 #endif
730
731 ret = -EPERM;
732 if ( !iomem_access_permitted(current->domain, mfn, mfn_end) ||
733 !iomem_access_permitted(d, mfn, mfn_end) )
734 break;
735
736 ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add);
737 if ( ret )
738 break;
739
740 if ( !paging_mode_translate(d) )
741 break;
742
743 if ( add )
744 {
745 printk(XENLOG_G_DEBUG
746 "memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n",
747 d->domain_id, gfn, mfn, nr_mfns);
748
749 ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
750 if ( ret < 0 )
751 printk(XENLOG_G_WARNING
752 "memory_map:fail: dom%d gfn=%lx mfn=%lx nr=%lx ret:%ld\n",
753 d->domain_id, gfn, mfn, nr_mfns, ret);
754 }
755 else
756 {
757 printk(XENLOG_G_DEBUG
758 "memory_map:remove: dom%d gfn=%lx mfn=%lx nr=%lx\n",
759 d->domain_id, gfn, mfn, nr_mfns);
760
761 ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
762 if ( ret < 0 && is_hardware_domain(current->domain) )
763 printk(XENLOG_ERR
764 "memory_map: error %ld removing dom%d access to [%lx,%lx]\n",
765 ret, d->domain_id, mfn, mfn_end);
766 }
767 break;
768 }
769
770 case XEN_DOMCTL_settimeoffset:
771 domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
772 break;
773
774 case XEN_DOMCTL_set_target:
775 {
776 struct domain *e;
777
778 ret = -ESRCH;
779 e = get_domain_by_id(op->u.set_target.target);
780 if ( e == NULL )
781 break;
782
783 ret = -EINVAL;
784 if ( (d == e) || (d->target != NULL) )
785 {
786 put_domain(e);
787 break;
788 }
789
790 ret = -EOPNOTSUPP;
791 if ( is_hvm_domain(e) )
792 ret = xsm_set_target(XSM_HOOK, d, e);
793 if ( ret )
794 {
795 put_domain(e);
796 break;
797 }
798
799 /* Hold reference on @e until we destroy @d. */
800 d->target = e;
801 break;
802 }
803
804 case XEN_DOMCTL_subscribe:
805 d->suspend_evtchn = op->u.subscribe.port;
806 break;
807
808 case XEN_DOMCTL_vm_event_op:
809 ret = vm_event_domctl(d, &op->u.vm_event_op);
810 if ( ret == 0 )
811 copyback = true;
812 break;
813
814 #ifdef CONFIG_VM_EVENT
815 case XEN_DOMCTL_set_access_required:
816 if ( unlikely(current->domain == d) ) /* no domain_pause() */
817 ret = -EPERM;
818 else
819 {
820 domain_pause(d);
821 arch_p2m_set_access_required(d,
822 op->u.access_required.access_required);
823 domain_unpause(d);
824 }
825 break;
826 #endif
827
828 case XEN_DOMCTL_set_virq_handler:
829 ret = set_global_virq_handler(d, op->u.set_virq_handler.virq);
830 break;
831
832 case XEN_DOMCTL_setvnumainfo:
833 {
834 struct vnuma_info *vnuma;
835
836 vnuma = vnuma_init(&op->u.vnuma, d);
837 if ( IS_ERR(vnuma) )
838 {
839 ret = PTR_ERR(vnuma);
840 break;
841 }
842
843 /* overwrite vnuma topology for domain. */
844 write_lock(&d->vnuma_rwlock);
845 vnuma_destroy(d->vnuma);
846 d->vnuma = vnuma;
847 write_unlock(&d->vnuma_rwlock);
848
849 break;
850 }
851
852 case XEN_DOMCTL_monitor_op:
853 ret = monitor_domctl(d, &op->u.monitor_op);
854 if ( !ret )
855 copyback = 1;
856 break;
857
858 case XEN_DOMCTL_assign_device:
859 case XEN_DOMCTL_test_assign_device:
860 case XEN_DOMCTL_deassign_device:
861 case XEN_DOMCTL_get_device_group:
862 ret = iommu_do_domctl(op, d, u_domctl);
863 break;
864
865 case XEN_DOMCTL_get_paging_mempool_size:
866 ret = arch_get_paging_mempool_size(d, &op->u.paging_mempool.size);
867 if ( !ret )
868 copyback = 1;
869 break;
870
871 case XEN_DOMCTL_set_paging_mempool_size:
872 ret = arch_set_paging_mempool_size(d, op->u.paging_mempool.size);
873
874 if ( ret == -ERESTART )
875 ret = hypercall_create_continuation(
876 __HYPERVISOR_domctl, "h", u_domctl);
877 break;
878
879 case XEN_DOMCTL_set_llc_colors:
880 if ( op->u.set_llc_colors.pad )
881 ret = -EINVAL;
882 else if ( llc_coloring_enabled )
883 ret = domain_set_llc_colors(d, &op->u.set_llc_colors);
884 else
885 ret = -EOPNOTSUPP;
886 break;
887
888 case XEN_DOMCTL_get_domain_state:
889 ret = xsm_get_domain_state(XSM_XS_PRIV, d);
890 if ( ret )
891 break;
892
893 copyback = 1;
894 ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
895 break;
896
897 default:
898 ret = arch_do_domctl(op, d, u_domctl);
899 break;
900 }
901
902 domctl_lock_release();
903
904 domctl_out_unlock_domonly:
905 if ( d && d != dom_io )
906 rcu_unlock_domain(d);
907
908 if ( copyback && __copy_to_guest(u_domctl, op, 1) )
909 ret = -EFAULT;
910
911 return ret;
912 }
913
build_assertions(void)914 static void __init __maybe_unused build_assertions(void)
915 {
916 struct xen_domctl d;
917
918 BUILD_BUG_ON(sizeof(d) != 16 /* header */ + 128 /* union */);
919 BUILD_BUG_ON(offsetof(typeof(d), u) != 16);
920 }
921
922 /*
923 * Local variables:
924 * mode: C
925 * c-file-style: "BSD"
926 * c-basic-offset: 4
927 * tab-width: 4
928 * indent-tabs-mode: nil
929 * End:
930 */
931