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(&current->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(&current->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(&current->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