ia64/xen-unstable

view xen/common/domctl.c @ 16519:62451388f630

Fix xenctl_cpumap_to_cpumask.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Dec 04 11:52:10 2007 +0000 (2007-12-04)
parents d2bef6551c12
children a583f3a7eafc
line source
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 */
9 #include <xen/config.h>
10 #include <xen/types.h>
11 #include <xen/lib.h>
12 #include <xen/mm.h>
13 #include <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/event.h>
16 #include <xen/domain_page.h>
17 #include <xen/trace.h>
18 #include <xen/console.h>
19 #include <xen/iocap.h>
20 #include <xen/rcupdate.h>
21 #include <xen/guest_access.h>
22 #include <xen/bitmap.h>
23 #include <xen/paging.h>
24 #include <asm/current.h>
25 #include <public/domctl.h>
26 #include <xsm/xsm.h>
28 extern long arch_do_domctl(
29 struct xen_domctl *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);
31 void cpumask_to_xenctl_cpumap(
32 struct xenctl_cpumap *xenctl_cpumap, cpumask_t *cpumask)
33 {
34 unsigned int guest_bytes, copy_bytes, i;
35 uint8_t zero = 0;
36 uint8_t bytemap[(NR_CPUS + 7) / 8];
38 if ( guest_handle_is_null(xenctl_cpumap->bitmap) )
39 return;
41 guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
42 copy_bytes = min_t(unsigned int, guest_bytes, sizeof(bytemap));
44 bitmap_long_to_byte(bytemap, cpus_addr(*cpumask), NR_CPUS);
46 if ( copy_bytes != 0 )
47 copy_to_guest(xenctl_cpumap->bitmap, bytemap, copy_bytes);
49 for ( i = copy_bytes; i < guest_bytes; i++ )
50 copy_to_guest_offset(xenctl_cpumap->bitmap, i, &zero, 1);
51 }
53 void xenctl_cpumap_to_cpumask(
54 cpumask_t *cpumask, struct xenctl_cpumap *xenctl_cpumap)
55 {
56 unsigned int guest_bytes, copy_bytes;
57 uint8_t bytemap[(NR_CPUS + 7) / 8];
59 if ( guest_handle_is_null(xenctl_cpumap->bitmap) )
60 return;
62 guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
63 copy_bytes = min_t(unsigned int, guest_bytes, sizeof(bytemap));
65 memset(bytemap, 0, sizeof(bytemap));
67 if ( copy_bytes != 0 )
68 {
69 copy_from_guest(bytemap, xenctl_cpumap->bitmap, copy_bytes);
70 if ( (xenctl_cpumap->nr_cpus & 7) && (guest_bytes <= sizeof(bytemap)) )
71 bytemap[guest_bytes-1] &= ~(0xff << (xenctl_cpumap->nr_cpus & 7));
72 }
74 bitmap_byte_to_long(cpus_addr(*cpumask), bytemap, NR_CPUS);
75 }
77 static inline int is_free_domid(domid_t dom)
78 {
79 struct domain *d;
81 if ( dom >= DOMID_FIRST_RESERVED )
82 return 0;
84 if ( (d = rcu_lock_domain_by_id(dom)) == NULL )
85 return 1;
87 rcu_unlock_domain(d);
88 return 0;
89 }
91 void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
92 {
93 struct vcpu *v;
94 u64 cpu_time = 0;
95 int flags = XEN_DOMINF_blocked;
96 struct vcpu_runstate_info runstate;
98 info->domain = d->domain_id;
99 info->nr_online_vcpus = 0;
101 /*
102 * - domain is marked as blocked only if all its vcpus are blocked
103 * - domain is marked as running if any of its vcpus is running
104 */
105 for_each_vcpu ( d, v )
106 {
107 vcpu_runstate_get(v, &runstate);
108 cpu_time += runstate.time[RUNSTATE_running];
109 info->max_vcpu_id = v->vcpu_id;
110 if ( !test_bit(_VPF_down, &v->pause_flags) )
111 {
112 if ( !(v->pause_flags & VPF_blocked) )
113 flags &= ~XEN_DOMINF_blocked;
114 if ( v->is_running )
115 flags |= XEN_DOMINF_running;
116 info->nr_online_vcpus++;
117 }
118 }
120 info->cpu_time = cpu_time;
122 info->flags = flags |
123 ((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying : 0) |
124 (d->is_shut_down ? XEN_DOMINF_shutdown : 0) |
125 (d->is_paused_by_controller ? XEN_DOMINF_paused : 0) |
126 (d->debugger_attached ? XEN_DOMINF_debugged : 0) |
127 d->shutdown_code << XEN_DOMINF_shutdownshift;
129 if ( is_hvm_domain(d) )
130 info->flags |= XEN_DOMINF_hvm_guest;
132 xsm_security_domaininfo(d, info);
134 info->tot_pages = d->tot_pages;
135 info->max_pages = d->max_pages;
136 info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
138 memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
139 }
141 static unsigned int default_vcpu0_location(void)
142 {
143 struct domain *d;
144 struct vcpu *v;
145 unsigned int i, cpu, cnt[NR_CPUS] = { 0 };
146 cpumask_t cpu_exclude_map;
148 /* Do an initial CPU placement. Pick the least-populated CPU. */
149 rcu_read_lock(&domlist_read_lock);
150 for_each_domain ( d )
151 for_each_vcpu ( d, v )
152 if ( !test_bit(_VPF_down, &v->pause_flags) )
153 cnt[v->processor]++;
154 rcu_read_unlock(&domlist_read_lock);
156 /*
157 * If we're on a HT system, we only auto-allocate to a non-primary HT. We
158 * favour high numbered CPUs in the event of a tie.
159 */
160 cpu = first_cpu(cpu_sibling_map[0]);
161 if ( cpus_weight(cpu_sibling_map[0]) > 1 )
162 cpu = next_cpu(cpu, cpu_sibling_map[0]);
163 cpu_exclude_map = cpu_sibling_map[0];
164 for_each_online_cpu ( i )
165 {
166 if ( cpu_isset(i, cpu_exclude_map) )
167 continue;
168 if ( (i == first_cpu(cpu_sibling_map[i])) &&
169 (cpus_weight(cpu_sibling_map[i]) > 1) )
170 continue;
171 cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
172 if ( cnt[i] <= cnt[cpu] )
173 cpu = i;
174 }
176 return cpu;
177 }
179 long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
180 {
181 long ret = 0;
182 struct xen_domctl curop, *op = &curop;
183 static DEFINE_SPINLOCK(domctl_lock);
185 if ( !IS_PRIV(current->domain) )
186 return -EPERM;
188 if ( copy_from_guest(op, u_domctl, 1) )
189 return -EFAULT;
191 if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
192 return -EACCES;
194 spin_lock(&domctl_lock);
196 if ( xsm_domctl(op) )
197 goto domctl_out;
199 switch ( op->cmd )
200 {
202 case XEN_DOMCTL_setvcpucontext:
203 {
204 struct domain *d = rcu_lock_domain_by_id(op->domain);
205 vcpu_guest_context_u c = { .nat = NULL };
206 unsigned int vcpu = op->u.vcpucontext.vcpu;
207 struct vcpu *v;
209 ret = -ESRCH;
210 if ( d == NULL )
211 break;
213 ret = -EINVAL;
214 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
215 goto svc_out;
217 if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
218 {
219 ret = vcpu_reset(v);
220 goto svc_out;
221 }
223 #ifdef CONFIG_COMPAT
224 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
225 < sizeof(struct compat_vcpu_guest_context));
226 #endif
227 ret = -ENOMEM;
228 if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
229 goto svc_out;
231 if ( !IS_COMPAT(v->domain) )
232 ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
233 #ifdef CONFIG_COMPAT
234 else
235 ret = copy_from_guest(c.cmp,
236 guest_handle_cast(op->u.vcpucontext.ctxt,
237 void), 1);
238 #endif
239 ret = ret ? -EFAULT : 0;
241 if ( ret == 0 )
242 {
243 domain_pause(d);
244 ret = arch_set_info_guest(v, c);
245 domain_unpause(d);
246 }
248 svc_out:
249 xfree(c.nat);
250 rcu_unlock_domain(d);
251 }
252 break;
254 case XEN_DOMCTL_pausedomain:
255 {
256 struct domain *d = rcu_lock_domain_by_id(op->domain);
257 ret = -ESRCH;
258 if ( d != NULL )
259 {
260 ret = -EINVAL;
261 if ( d != current->domain )
262 {
263 domain_pause_by_systemcontroller(d);
264 ret = 0;
265 }
266 rcu_unlock_domain(d);
267 }
268 }
269 break;
271 case XEN_DOMCTL_unpausedomain:
272 {
273 struct domain *d = rcu_lock_domain_by_id(op->domain);
275 ret = -ESRCH;
276 if ( d == NULL )
277 break;
278 domain_unpause_by_systemcontroller(d);
279 rcu_unlock_domain(d);
280 ret = 0;
281 }
282 break;
284 case XEN_DOMCTL_resumedomain:
285 {
286 struct domain *d = rcu_lock_domain_by_id(op->domain);
288 ret = -ESRCH;
289 if ( d == NULL )
290 break;
292 domain_resume(d);
293 rcu_unlock_domain(d);
294 ret = 0;
295 }
296 break;
298 case XEN_DOMCTL_createdomain:
299 {
300 struct domain *d;
301 domid_t dom;
302 static domid_t rover = 0;
303 unsigned int domcr_flags;
305 ret = -EINVAL;
306 if ( supervisor_mode_kernel ||
307 (op->u.createdomain.flags & ~XEN_DOMCTL_CDF_hvm_guest) )
308 break;
310 dom = op->domain;
311 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
312 {
313 ret = -EINVAL;
314 if ( !is_free_domid(dom) )
315 break;
316 }
317 else
318 {
319 for ( dom = rover + 1; dom != rover; dom++ )
320 {
321 if ( dom == DOMID_FIRST_RESERVED )
322 dom = 0;
323 if ( is_free_domid(dom) )
324 break;
325 }
327 ret = -ENOMEM;
328 if ( dom == rover )
329 break;
331 rover = dom;
332 }
334 domcr_flags = 0;
335 if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hvm_guest )
336 domcr_flags |= DOMCRF_hvm;
338 ret = -ENOMEM;
339 d = domain_create(dom, domcr_flags, op->u.createdomain.ssidref);
340 if ( d == NULL )
341 break;
343 ret = 0;
345 memcpy(d->handle, op->u.createdomain.handle,
346 sizeof(xen_domain_handle_t));
348 op->domain = d->domain_id;
349 if ( copy_to_guest(u_domctl, op, 1) )
350 ret = -EFAULT;
351 }
352 break;
354 case XEN_DOMCTL_max_vcpus:
355 {
356 struct domain *d;
357 unsigned int i, max = op->u.max_vcpus.max, cpu;
359 ret = -EINVAL;
360 if ( max > MAX_VIRT_CPUS )
361 break;
363 ret = -ESRCH;
364 if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
365 break;
367 /* Needed, for example, to ensure writable p.t. state is synced. */
368 domain_pause(d);
370 /* We cannot reduce maximum VCPUs. */
371 ret = -EINVAL;
372 if ( (max != MAX_VIRT_CPUS) && (d->vcpu[max] != NULL) )
373 goto maxvcpu_out;
375 ret = -ENOMEM;
376 for ( i = 0; i < max; i++ )
377 {
378 if ( d->vcpu[i] != NULL )
379 continue;
381 cpu = (i == 0) ?
382 default_vcpu0_location() :
383 (d->vcpu[i-1]->processor + 1) % num_online_cpus();
385 if ( alloc_vcpu(d, i, cpu) == NULL )
386 goto maxvcpu_out;
387 }
389 ret = 0;
391 maxvcpu_out:
392 domain_unpause(d);
393 rcu_unlock_domain(d);
394 }
395 break;
397 case XEN_DOMCTL_destroydomain:
398 {
399 struct domain *d = rcu_lock_domain_by_id(op->domain);
400 ret = -ESRCH;
401 if ( d != NULL )
402 {
403 domain_kill(d);
404 rcu_unlock_domain(d);
405 }
406 }
407 break;
409 case XEN_DOMCTL_setvcpuaffinity:
410 case XEN_DOMCTL_getvcpuaffinity:
411 {
412 domid_t dom = op->domain;
413 struct domain *d = rcu_lock_domain_by_id(dom);
414 struct vcpu *v;
415 cpumask_t new_affinity;
417 ret = -ESRCH;
418 if ( d == NULL )
419 break;
421 ret = -EINVAL;
422 if ( op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS )
423 goto vcpuaffinity_out;
425 ret = -ESRCH;
426 if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
427 goto vcpuaffinity_out;
429 if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
430 {
431 xenctl_cpumap_to_cpumask(
432 &new_affinity, &op->u.vcpuaffinity.cpumap);
433 ret = vcpu_set_affinity(v, &new_affinity);
434 }
435 else
436 {
437 cpumask_to_xenctl_cpumap(
438 &op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
439 ret = 0;
440 }
442 vcpuaffinity_out:
443 rcu_unlock_domain(d);
444 }
445 break;
447 case XEN_DOMCTL_scheduler_op:
448 {
449 struct domain *d;
451 ret = -ESRCH;
452 if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
453 break;
455 ret = sched_adjust(d, &op->u.scheduler_op);
456 if ( copy_to_guest(u_domctl, op, 1) )
457 ret = -EFAULT;
459 rcu_unlock_domain(d);
460 }
461 break;
463 case XEN_DOMCTL_getdomaininfo:
464 {
465 struct domain *d;
466 domid_t dom = op->domain;
468 rcu_read_lock(&domlist_read_lock);
470 for_each_domain ( d )
471 if ( d->domain_id >= dom )
472 break;
474 if ( d == NULL )
475 {
476 rcu_read_unlock(&domlist_read_lock);
477 ret = -ESRCH;
478 break;
479 }
481 getdomaininfo(d, &op->u.getdomaininfo);
483 op->domain = op->u.getdomaininfo.domain;
484 if ( copy_to_guest(u_domctl, op, 1) )
485 ret = -EFAULT;
487 rcu_read_unlock(&domlist_read_lock);
488 }
489 break;
491 case XEN_DOMCTL_getvcpucontext:
492 {
493 vcpu_guest_context_u c = { .nat = NULL };
494 struct domain *d;
495 struct vcpu *v;
497 ret = -ESRCH;
498 if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
499 break;
501 ret = -EINVAL;
502 if ( op->u.vcpucontext.vcpu >= MAX_VIRT_CPUS )
503 goto getvcpucontext_out;
505 ret = -ESRCH;
506 if ( (v = d->vcpu[op->u.vcpucontext.vcpu]) == NULL )
507 goto getvcpucontext_out;
509 ret = -ENODATA;
510 if ( !v->is_initialised )
511 goto getvcpucontext_out;
513 #ifdef CONFIG_COMPAT
514 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
515 < sizeof(struct compat_vcpu_guest_context));
516 #endif
517 ret = -ENOMEM;
518 if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
519 goto getvcpucontext_out;
521 if ( v != current )
522 vcpu_pause(v);
524 arch_get_info_guest(v, c);
525 ret = 0;
527 if ( v != current )
528 vcpu_unpause(v);
530 if ( !IS_COMPAT(v->domain) )
531 ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
532 #ifdef CONFIG_COMPAT
533 else
534 ret = copy_to_guest(guest_handle_cast(op->u.vcpucontext.ctxt,
535 void), c.cmp, 1);
536 #endif
538 if ( copy_to_guest(u_domctl, op, 1) || ret )
539 ret = -EFAULT;
541 getvcpucontext_out:
542 xfree(c.nat);
543 rcu_unlock_domain(d);
544 }
545 break;
547 case XEN_DOMCTL_getvcpuinfo:
548 {
549 struct domain *d;
550 struct vcpu *v;
551 struct vcpu_runstate_info runstate;
553 ret = -ESRCH;
554 if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
555 break;
557 ret = -EINVAL;
558 if ( op->u.getvcpuinfo.vcpu >= MAX_VIRT_CPUS )
559 goto getvcpuinfo_out;
561 ret = -ESRCH;
562 if ( (v = d->vcpu[op->u.getvcpuinfo.vcpu]) == NULL )
563 goto getvcpuinfo_out;
565 vcpu_runstate_get(v, &runstate);
567 op->u.getvcpuinfo.online = !test_bit(_VPF_down, &v->pause_flags);
568 op->u.getvcpuinfo.blocked = test_bit(_VPF_blocked, &v->pause_flags);
569 op->u.getvcpuinfo.running = v->is_running;
570 op->u.getvcpuinfo.cpu_time = runstate.time[RUNSTATE_running];
571 op->u.getvcpuinfo.cpu = v->processor;
572 ret = 0;
574 if ( copy_to_guest(u_domctl, op, 1) )
575 ret = -EFAULT;
577 getvcpuinfo_out:
578 rcu_unlock_domain(d);
579 }
580 break;
582 case XEN_DOMCTL_max_mem:
583 {
584 struct domain *d;
585 unsigned long new_max;
587 ret = -ESRCH;
588 d = rcu_lock_domain_by_id(op->domain);
589 if ( d == NULL )
590 break;
592 ret = -EINVAL;
593 new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT-10);
595 spin_lock(&d->page_alloc_lock);
596 if ( new_max >= d->tot_pages )
597 {
598 ret = guest_physmap_max_mem_pages(d, new_max);
599 if ( ret != 0 )
600 break;
601 d->max_pages = new_max;
602 ret = 0;
603 }
604 spin_unlock(&d->page_alloc_lock);
606 rcu_unlock_domain(d);
607 }
608 break;
610 case XEN_DOMCTL_setdomainhandle:
611 {
612 struct domain *d;
614 ret = -ESRCH;
615 d = rcu_lock_domain_by_id(op->domain);
616 if ( d == NULL )
617 break;
619 memcpy(d->handle, op->u.setdomainhandle.handle,
620 sizeof(xen_domain_handle_t));
621 rcu_unlock_domain(d);
622 ret = 0;
623 }
624 break;
626 case XEN_DOMCTL_setdebugging:
627 {
628 struct domain *d;
630 ret = -ESRCH;
631 d = rcu_lock_domain_by_id(op->domain);
632 if ( d == NULL )
633 break;
635 domain_pause(d);
636 d->debugger_attached = !!op->u.setdebugging.enable;
637 domain_unpause(d); /* causes guest to latch new status */
638 rcu_unlock_domain(d);
639 ret = 0;
640 }
641 break;
643 case XEN_DOMCTL_irq_permission:
644 {
645 struct domain *d;
646 unsigned int pirq = op->u.irq_permission.pirq;
648 ret = -EINVAL;
649 if ( pirq >= NR_IRQS )
650 break;
652 ret = -ESRCH;
653 d = rcu_lock_domain_by_id(op->domain);
654 if ( d == NULL )
655 break;
657 if ( op->u.irq_permission.allow_access )
658 ret = irq_permit_access(d, pirq);
659 else
660 ret = irq_deny_access(d, pirq);
662 rcu_unlock_domain(d);
663 }
664 break;
666 case XEN_DOMCTL_iomem_permission:
667 {
668 struct domain *d;
669 unsigned long mfn = op->u.iomem_permission.first_mfn;
670 unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
672 ret = -EINVAL;
673 if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
674 break;
676 ret = -ESRCH;
677 d = rcu_lock_domain_by_id(op->domain);
678 if ( d == NULL )
679 break;
681 if ( op->u.iomem_permission.allow_access )
682 ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
683 else
684 ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
686 rcu_unlock_domain(d);
687 }
688 break;
690 case XEN_DOMCTL_settimeoffset:
691 {
692 struct domain *d;
694 ret = -ESRCH;
695 d = rcu_lock_domain_by_id(op->domain);
696 if ( d != NULL )
697 {
698 d->time_offset_seconds = op->u.settimeoffset.time_offset_seconds;
699 rcu_unlock_domain(d);
700 ret = 0;
701 }
702 }
703 break;
705 default:
706 ret = arch_do_domctl(op, u_domctl);
707 break;
708 }
710 domctl_out:
711 spin_unlock(&domctl_lock);
713 return ret;
714 }
716 /*
717 * Local variables:
718 * mode: C
719 * c-set-style: "BSD"
720 * c-basic-offset: 4
721 * tab-width: 4
722 * indent-tabs-mode: nil
723 * End:
724 */