ia64/xen-unstable

view xen/common/domctl.c @ 13608:30af6cfdb05c

Make domctl/sysctl interfaces 32-/64-bit invariant.
This kills off a fair amount of unpleasant CONFIG_COMPAT shimming and
avoids needing to keep the compat paths in sync as these interfaces
continue to develop.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Jan 24 16:33:19 2007 +0000 (2007-01-24)
parents 701afa77106a
children 271ffb1c12eb
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/guest_access.h>
21 #include <xen/bitmap.h>
22 #include <asm/current.h>
23 #include <public/domctl.h>
24 #include <acm/acm_hooks.h>
26 extern long arch_do_domctl(
27 struct xen_domctl *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);
29 void cpumask_to_xenctl_cpumap(
30 struct xenctl_cpumap *xenctl_cpumap, cpumask_t *cpumask)
31 {
32 unsigned int guest_bytes, copy_bytes, i;
33 uint8_t zero = 0;
34 uint8_t bytemap[(NR_CPUS + 7) / 8];
36 if ( guest_handle_is_null(xenctl_cpumap->bitmap) )
37 return;
39 guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
40 copy_bytes = min_t(unsigned int, guest_bytes, sizeof(bytemap));
42 bitmap_long_to_byte(bytemap, cpus_addr(*cpumask), NR_CPUS);
44 copy_to_guest(xenctl_cpumap->bitmap, &bytemap[0], copy_bytes);
46 for ( i = copy_bytes; i < guest_bytes; i++ )
47 copy_to_guest_offset(xenctl_cpumap->bitmap, i, &zero, 1);
48 }
50 void xenctl_cpumap_to_cpumask(
51 cpumask_t *cpumask, struct xenctl_cpumap *xenctl_cpumap)
52 {
53 unsigned int guest_bytes, copy_bytes;
54 uint8_t bytemap[(NR_CPUS + 7) / 8];
56 guest_bytes = (xenctl_cpumap->nr_cpus + 7) / 8;
57 copy_bytes = min_t(unsigned int, guest_bytes, sizeof(bytemap));
59 cpus_clear(*cpumask);
61 if ( guest_handle_is_null(xenctl_cpumap->bitmap) )
62 return;
64 copy_from_guest(&bytemap[0], xenctl_cpumap->bitmap, copy_bytes);
66 bitmap_byte_to_long(cpus_addr(*cpumask), bytemap, NR_CPUS);
67 }
69 static inline int is_free_domid(domid_t dom)
70 {
71 struct domain *d;
73 if ( dom >= DOMID_FIRST_RESERVED )
74 return 0;
76 if ( (d = find_domain_by_id(dom)) == NULL )
77 return 1;
79 put_domain(d);
80 return 0;
81 }
83 void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
84 {
85 struct vcpu *v;
86 u64 cpu_time = 0;
87 int flags = XEN_DOMINF_blocked;
88 struct vcpu_runstate_info runstate;
90 info->domain = d->domain_id;
91 info->nr_online_vcpus = 0;
93 /*
94 * - domain is marked as blocked only if all its vcpus are blocked
95 * - domain is marked as running if any of its vcpus is running
96 */
97 for_each_vcpu ( d, v )
98 {
99 vcpu_runstate_get(v, &runstate);
100 cpu_time += runstate.time[RUNSTATE_running];
101 info->max_vcpu_id = v->vcpu_id;
102 if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
103 {
104 if ( !(v->vcpu_flags & VCPUF_blocked) )
105 flags &= ~XEN_DOMINF_blocked;
106 if ( v->vcpu_flags & VCPUF_running )
107 flags |= XEN_DOMINF_running;
108 info->nr_online_vcpus++;
109 }
110 }
112 info->cpu_time = cpu_time;
114 info->flags = flags |
115 ((d->domain_flags & DOMF_dying) ? XEN_DOMINF_dying : 0) |
116 ((d->domain_flags & DOMF_shutdown) ? XEN_DOMINF_shutdown : 0) |
117 ((d->domain_flags & DOMF_ctrl_pause) ? XEN_DOMINF_paused : 0) |
118 d->shutdown_code << XEN_DOMINF_shutdownshift;
120 if ( is_hvm_domain(d) )
121 info->flags |= XEN_DOMINF_hvm_guest;
123 if ( d->ssid != NULL )
124 info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
125 else
126 info->ssidref = ACM_DEFAULT_SSID;
128 info->tot_pages = d->tot_pages;
129 info->max_pages = d->max_pages;
130 info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
132 memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
133 }
135 static unsigned int default_vcpu0_location(void)
136 {
137 struct domain *d;
138 struct vcpu *v;
139 unsigned int i, cpu, cnt[NR_CPUS] = { 0 };
140 cpumask_t cpu_exclude_map;
142 /* Do an initial CPU placement. Pick the least-populated CPU. */
143 read_lock(&domlist_lock);
144 for_each_domain ( d )
145 for_each_vcpu ( d, v )
146 if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
147 cnt[v->processor]++;
148 read_unlock(&domlist_lock);
150 /*
151 * If we're on a HT system, we only auto-allocate to a non-primary HT. We
152 * favour high numbered CPUs in the event of a tie.
153 */
154 cpu = first_cpu(cpu_sibling_map[0]);
155 if ( cpus_weight(cpu_sibling_map[0]) > 1 )
156 cpu = next_cpu(cpu, cpu_sibling_map[0]);
157 cpu_exclude_map = cpu_sibling_map[0];
158 for_each_online_cpu ( i )
159 {
160 if ( cpu_isset(i, cpu_exclude_map) )
161 continue;
162 if ( (i == first_cpu(cpu_sibling_map[i])) &&
163 (cpus_weight(cpu_sibling_map[i]) > 1) )
164 continue;
165 cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
166 if ( cnt[i] <= cnt[cpu] )
167 cpu = i;
168 }
170 return cpu;
171 }
173 long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
174 {
175 long ret = 0;
176 struct xen_domctl curop, *op = &curop;
177 void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
178 static DEFINE_SPINLOCK(domctl_lock);
180 if ( !IS_PRIV(current->domain) )
181 return -EPERM;
183 if ( copy_from_guest(op, u_domctl, 1) )
184 return -EFAULT;
186 if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
187 return -EACCES;
189 if ( acm_pre_domctl(op, &ssid) )
190 return -EPERM;
192 spin_lock(&domctl_lock);
194 switch ( op->cmd )
195 {
197 case XEN_DOMCTL_setvcpucontext:
198 {
199 struct domain *d = find_domain_by_id(op->domain);
200 vcpu_guest_context_u c = { .nat = NULL };
201 unsigned int vcpu = op->u.vcpucontext.vcpu;
202 struct vcpu *v;
204 ret = -ESRCH;
205 if ( d == NULL )
206 break;
208 ret = -EINVAL;
209 if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
210 goto svc_out;
212 if ( guest_handle_is_null(op->u.vcpucontext.ctxt) )
213 {
214 ret = vcpu_reset(v);
215 goto svc_out;
216 }
218 #ifdef CONFIG_COMPAT
219 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
220 < sizeof(struct compat_vcpu_guest_context));
221 #endif
222 ret = -ENOMEM;
223 if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
224 goto svc_out;
226 if ( !IS_COMPAT(v->domain) )
227 ret = copy_from_guest(c.nat, op->u.vcpucontext.ctxt, 1);
228 #ifdef CONFIG_COMPAT
229 else
230 ret = copy_from_guest(c.cmp,
231 guest_handle_cast(op->u.vcpucontext.ctxt,
232 void), 1);
233 #endif
234 ret = ret ? -EFAULT : 0;
236 if ( ret == 0 )
237 {
238 domain_pause(d);
239 ret = arch_set_info_guest(v, c);
240 domain_unpause(d);
241 }
243 svc_out:
244 xfree(c.nat);
245 put_domain(d);
246 }
247 break;
249 case XEN_DOMCTL_pausedomain:
250 {
251 struct domain *d = find_domain_by_id(op->domain);
252 ret = -ESRCH;
253 if ( d != NULL )
254 {
255 ret = -EINVAL;
256 if ( d != current->domain )
257 {
258 domain_pause_by_systemcontroller(d);
259 ret = 0;
260 }
261 put_domain(d);
262 }
263 }
264 break;
266 case XEN_DOMCTL_unpausedomain:
267 {
268 struct domain *d = find_domain_by_id(op->domain);
269 ret = -ESRCH;
270 if ( d != NULL )
271 {
272 ret = -EINVAL;
273 if ( (d != current->domain) && (d->vcpu[0] != NULL) &&
274 test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
275 {
276 domain_unpause_by_systemcontroller(d);
277 ret = 0;
278 }
279 put_domain(d);
280 }
281 }
282 break;
284 case XEN_DOMCTL_resumedomain:
285 {
286 struct domain *d = find_domain_by_id(op->domain);
287 struct vcpu *v;
289 ret = -ESRCH;
290 if ( d != NULL )
291 {
292 ret = 0;
293 if ( test_and_clear_bit(_DOMF_shutdown, &d->domain_flags) )
294 for_each_vcpu ( d, v )
295 vcpu_wake(v);
296 put_domain(d);
297 }
298 }
299 break;
301 case XEN_DOMCTL_createdomain:
302 {
303 struct domain *d;
304 domid_t dom;
305 static domid_t rover = 0;
306 unsigned int domcr_flags;
308 if ( supervisor_mode_kernel ||
309 (op->u.createdomain.flags & ~XEN_DOMCTL_CDF_hvm_guest) )
310 return -EINVAL;
312 dom = op->domain;
313 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
314 {
315 ret = -EINVAL;
316 if ( !is_free_domid(dom) )
317 break;
318 }
319 else
320 {
321 for ( dom = rover + 1; dom != rover; dom++ )
322 {
323 if ( dom == DOMID_FIRST_RESERVED )
324 dom = 0;
325 if ( is_free_domid(dom) )
326 break;
327 }
329 ret = -ENOMEM;
330 if ( dom == rover )
331 break;
333 rover = dom;
334 }
336 domcr_flags = 0;
337 if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hvm_guest )
338 domcr_flags |= DOMCRF_hvm;
340 ret = -ENOMEM;
341 if ( (d = domain_create(dom, domcr_flags)) == NULL )
342 break;
344 #ifdef CONFIG_COMPAT
345 if ( IS_COMPAT(current->domain) && ((ret = switch_compat(d)) != 0) )
346 break;
347 #endif
349 ret = 0;
351 memcpy(d->handle, op->u.createdomain.handle,
352 sizeof(xen_domain_handle_t));
354 op->domain = d->domain_id;
355 if ( copy_to_guest(u_domctl, op, 1) )
356 ret = -EFAULT;
357 }
358 break;
360 case XEN_DOMCTL_max_vcpus:
361 {
362 struct domain *d;
363 unsigned int i, max = op->u.max_vcpus.max, cpu;
365 ret = -EINVAL;
366 if ( max > MAX_VIRT_CPUS )
367 break;
369 ret = -ESRCH;
370 if ( (d = find_domain_by_id(op->domain)) == NULL )
371 break;
373 /* Needed, for example, to ensure writable p.t. state is synced. */
374 domain_pause(d);
376 /* We cannot reduce maximum VCPUs. */
377 ret = -EINVAL;
378 if ( (max != MAX_VIRT_CPUS) && (d->vcpu[max] != NULL) )
379 goto maxvcpu_out;
381 ret = -ENOMEM;
382 for ( i = 0; i < max; i++ )
383 {
384 if ( d->vcpu[i] != NULL )
385 continue;
387 cpu = (i == 0) ?
388 default_vcpu0_location() :
389 (d->vcpu[i-1]->processor + 1) % num_online_cpus();
391 if ( alloc_vcpu(d, i, cpu) == NULL )
392 goto maxvcpu_out;
393 }
395 ret = 0;
397 maxvcpu_out:
398 domain_unpause(d);
399 put_domain(d);
400 }
401 break;
403 case XEN_DOMCTL_destroydomain:
404 {
405 struct domain *d = find_domain_by_id(op->domain);
406 ret = -ESRCH;
407 if ( d != NULL )
408 {
409 ret = -EINVAL;
410 if ( d != current->domain )
411 {
412 domain_kill(d);
413 ret = 0;
414 }
415 put_domain(d);
416 }
417 }
418 break;
420 case XEN_DOMCTL_setvcpuaffinity:
421 case XEN_DOMCTL_getvcpuaffinity:
422 {
423 domid_t dom = op->domain;
424 struct domain *d = find_domain_by_id(dom);
425 struct vcpu *v;
426 cpumask_t new_affinity;
428 ret = -ESRCH;
429 if ( d == NULL )
430 break;
432 ret = -EINVAL;
433 if ( op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS )
434 goto vcpuaffinity_out;
436 ret = -ESRCH;
437 if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
438 goto vcpuaffinity_out;
440 if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
441 {
442 xenctl_cpumap_to_cpumask(
443 &new_affinity, &op->u.vcpuaffinity.cpumap);
444 ret = vcpu_set_affinity(v, &new_affinity);
445 }
446 else
447 {
448 cpumask_to_xenctl_cpumap(
449 &op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
450 ret = 0;
451 }
453 vcpuaffinity_out:
454 put_domain(d);
455 }
456 break;
458 case XEN_DOMCTL_scheduler_op:
459 {
460 struct domain *d;
462 ret = -ESRCH;
463 if ( (d = find_domain_by_id(op->domain)) == NULL )
464 break;
466 ret = sched_adjust(d, &op->u.scheduler_op);
467 if ( copy_to_guest(u_domctl, op, 1) )
468 ret = -EFAULT;
470 put_domain(d);
471 }
472 break;
474 case XEN_DOMCTL_getdomaininfo:
475 {
476 struct domain *d;
477 domid_t dom;
479 dom = op->domain;
480 if ( dom == DOMID_SELF )
481 dom = current->domain->domain_id;
483 read_lock(&domlist_lock);
485 for_each_domain ( d )
486 {
487 if ( d->domain_id >= dom )
488 break;
489 }
491 if ( (d == NULL) || !get_domain(d) )
492 {
493 read_unlock(&domlist_lock);
494 ret = -ESRCH;
495 break;
496 }
498 read_unlock(&domlist_lock);
500 getdomaininfo(d, &op->u.getdomaininfo);
502 op->domain = op->u.getdomaininfo.domain;
503 if ( copy_to_guest(u_domctl, op, 1) )
504 ret = -EFAULT;
506 put_domain(d);
507 }
508 break;
510 case XEN_DOMCTL_getvcpucontext:
511 {
512 vcpu_guest_context_u c = { .nat = NULL };
513 struct domain *d;
514 struct vcpu *v;
516 ret = -ESRCH;
517 if ( (d = find_domain_by_id(op->domain)) == NULL )
518 break;
520 ret = -EINVAL;
521 if ( op->u.vcpucontext.vcpu >= MAX_VIRT_CPUS )
522 goto getvcpucontext_out;
524 ret = -ESRCH;
525 if ( (v = d->vcpu[op->u.vcpucontext.vcpu]) == NULL )
526 goto getvcpucontext_out;
528 ret = -ENODATA;
529 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
530 goto getvcpucontext_out;
532 #ifdef CONFIG_COMPAT
533 BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
534 < sizeof(struct compat_vcpu_guest_context));
535 #endif
536 ret = -ENOMEM;
537 if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
538 goto getvcpucontext_out;
540 if ( v != current )
541 vcpu_pause(v);
543 arch_get_info_guest(v, c);
544 ret = 0;
546 if ( v != current )
547 vcpu_unpause(v);
549 if ( !IS_COMPAT(v->domain) )
550 ret = copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1);
551 #ifdef CONFIG_COMPAT
552 else
553 ret = copy_to_guest(guest_handle_cast(op->u.vcpucontext.ctxt,
554 void), c.cmp, 1);
555 #endif
557 if ( copy_to_guest(u_domctl, op, 1) || ret )
558 ret = -EFAULT;
560 getvcpucontext_out:
561 xfree(c.nat);
562 put_domain(d);
563 }
564 break;
566 case XEN_DOMCTL_getvcpuinfo:
567 {
568 struct domain *d;
569 struct vcpu *v;
570 struct vcpu_runstate_info runstate;
572 ret = -ESRCH;
573 if ( (d = find_domain_by_id(op->domain)) == NULL )
574 break;
576 ret = -EINVAL;
577 if ( op->u.getvcpuinfo.vcpu >= MAX_VIRT_CPUS )
578 goto getvcpuinfo_out;
580 ret = -ESRCH;
581 if ( (v = d->vcpu[op->u.getvcpuinfo.vcpu]) == NULL )
582 goto getvcpuinfo_out;
584 vcpu_runstate_get(v, &runstate);
586 op->u.getvcpuinfo.online = !test_bit(_VCPUF_down, &v->vcpu_flags);
587 op->u.getvcpuinfo.blocked = test_bit(_VCPUF_blocked, &v->vcpu_flags);
588 op->u.getvcpuinfo.running = test_bit(_VCPUF_running, &v->vcpu_flags);
589 op->u.getvcpuinfo.cpu_time = runstate.time[RUNSTATE_running];
590 op->u.getvcpuinfo.cpu = v->processor;
591 ret = 0;
593 if ( copy_to_guest(u_domctl, op, 1) )
594 ret = -EFAULT;
596 getvcpuinfo_out:
597 put_domain(d);
598 }
599 break;
601 case XEN_DOMCTL_max_mem:
602 {
603 struct domain *d;
604 unsigned long new_max;
606 ret = -ESRCH;
607 d = find_domain_by_id(op->domain);
608 if ( d == NULL )
609 break;
611 ret = -EINVAL;
612 new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT-10);
614 spin_lock(&d->page_alloc_lock);
615 if ( new_max >= d->tot_pages )
616 {
617 d->max_pages = new_max;
618 ret = 0;
619 }
620 spin_unlock(&d->page_alloc_lock);
622 put_domain(d);
623 }
624 break;
626 case XEN_DOMCTL_setdomainhandle:
627 {
628 struct domain *d;
629 ret = -ESRCH;
630 d = find_domain_by_id(op->domain);
631 if ( d != NULL )
632 {
633 memcpy(d->handle, op->u.setdomainhandle.handle,
634 sizeof(xen_domain_handle_t));
635 put_domain(d);
636 ret = 0;
637 }
638 }
639 break;
641 case XEN_DOMCTL_setdebugging:
642 {
643 struct domain *d;
644 ret = -ESRCH;
645 d = find_domain_by_id(op->domain);
646 if ( d != NULL )
647 {
648 if ( op->u.setdebugging.enable )
649 set_bit(_DOMF_debugging, &d->domain_flags);
650 else
651 clear_bit(_DOMF_debugging, &d->domain_flags);
652 put_domain(d);
653 ret = 0;
654 }
655 }
656 break;
658 case XEN_DOMCTL_irq_permission:
659 {
660 struct domain *d;
661 unsigned int pirq = op->u.irq_permission.pirq;
663 ret = -EINVAL;
664 if ( pirq >= NR_IRQS )
665 break;
667 ret = -ESRCH;
668 d = find_domain_by_id(op->domain);
669 if ( d == NULL )
670 break;
672 if ( op->u.irq_permission.allow_access )
673 ret = irq_permit_access(d, pirq);
674 else
675 ret = irq_deny_access(d, pirq);
677 put_domain(d);
678 }
679 break;
681 case XEN_DOMCTL_iomem_permission:
682 {
683 struct domain *d;
684 unsigned long mfn = op->u.iomem_permission.first_mfn;
685 unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
687 ret = -EINVAL;
688 if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
689 break;
691 ret = -ESRCH;
692 d = find_domain_by_id(op->domain);
693 if ( d == NULL )
694 break;
696 if ( op->u.iomem_permission.allow_access )
697 ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
698 else
699 ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
701 put_domain(d);
702 }
703 break;
705 case XEN_DOMCTL_settimeoffset:
706 {
707 struct domain *d;
709 ret = -ESRCH;
710 d = find_domain_by_id(op->domain);
711 if ( d != NULL )
712 {
713 d->time_offset_seconds = op->u.settimeoffset.time_offset_seconds;
714 put_domain(d);
715 ret = 0;
716 }
717 }
718 break;
720 default:
721 ret = arch_do_domctl(op, u_domctl);
722 break;
723 }
725 spin_unlock(&domctl_lock);
727 if ( ret == 0 )
728 acm_post_domctl(op, &ssid);
729 else
730 acm_fail_domctl(op, &ssid);
732 return ret;
733 }
735 /*
736 * Local variables:
737 * mode: C
738 * c-set-style: "BSD"
739 * c-basic-offset: 4
740 * tab-width: 4
741 * indent-tabs-mode: nil
742 * End:
743 */