debuggers.hg

view xen/common/domain.c @ 21960:49254cab8465

numa: Small tweaks to domain_update_node_affinity() and its callers.

From: Andrew Jones <drjones@redhat.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 04 17:10:46 2010 +0100 (2010-08-04)
parents 581ebaa7e2da
children fe21e474c694
line source
1 /******************************************************************************
2 * domain.c
3 *
4 * Generic domain-handling functions.
5 */
7 #include <xen/config.h>
8 #include <xen/compat.h>
9 #include <xen/init.h>
10 #include <xen/lib.h>
11 #include <xen/ctype.h>
12 #include <xen/errno.h>
13 #include <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/mm.h>
16 #include <xen/event.h>
17 #include <xen/time.h>
18 #include <xen/console.h>
19 #include <xen/softirq.h>
20 #include <xen/tasklet.h>
21 #include <xen/domain_page.h>
22 #include <xen/rangeset.h>
23 #include <xen/guest_access.h>
24 #include <xen/hypercall.h>
25 #include <xen/delay.h>
26 #include <xen/shutdown.h>
27 #include <xen/percpu.h>
28 #include <xen/multicall.h>
29 #include <xen/rcupdate.h>
30 #include <acpi/cpufreq/cpufreq.h>
31 #include <asm/debugger.h>
32 #include <public/sched.h>
33 #include <public/sysctl.h>
34 #include <public/vcpu.h>
35 #include <xsm/xsm.h>
36 #include <xen/trace.h>
37 #include <xen/tmem.h>
39 /* Linux config option: propageted to domain0 */
40 /* xen_processor_pmbits: xen control Cx, Px, ... */
41 unsigned int xen_processor_pmbits = XEN_PROCESSOR_PM_PX;
43 /* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */
44 static unsigned int opt_dom0_vcpus_pin;
45 boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
47 /* set xen as default cpufreq */
48 enum cpufreq_controller cpufreq_controller = FREQCTL_xen;
50 static void __init setup_cpufreq_option(char *str)
51 {
52 char *arg;
54 if ( !strcmp(str, "dom0-kernel") )
55 {
56 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
57 cpufreq_controller = FREQCTL_dom0_kernel;
58 opt_dom0_vcpus_pin = 1;
59 return;
60 }
62 if ( !strcmp(str, "none") )
63 {
64 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
65 cpufreq_controller = FREQCTL_none;
66 return;
67 }
69 if ( (arg = strpbrk(str, ",:")) != NULL )
70 *arg++ = '\0';
72 if ( !strcmp(str, "xen") )
73 if ( arg && *arg )
74 cpufreq_cmdline_parse(arg);
75 }
76 custom_param("cpufreq", setup_cpufreq_option);
78 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
79 DEFINE_SPINLOCK(domlist_update_lock);
80 DEFINE_RCU_READ_LOCK(domlist_read_lock);
82 #define DOMAIN_HASH_SIZE 256
83 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
84 static struct domain *domain_hash[DOMAIN_HASH_SIZE];
85 struct domain *domain_list;
87 struct domain *dom0;
89 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
91 vcpu_info_t dummy_vcpu_info;
93 int current_domain_id(void)
94 {
95 return current->domain->domain_id;
96 }
98 static void __domain_finalise_shutdown(struct domain *d)
99 {
100 struct vcpu *v;
102 BUG_ON(!spin_is_locked(&d->shutdown_lock));
104 if ( d->is_shut_down )
105 return;
107 for_each_vcpu ( d, v )
108 if ( !v->paused_for_shutdown )
109 return;
111 d->is_shut_down = 1;
112 if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn )
113 evtchn_send(d, d->suspend_evtchn);
114 else
115 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
116 }
118 static void vcpu_check_shutdown(struct vcpu *v)
119 {
120 struct domain *d = v->domain;
122 spin_lock(&d->shutdown_lock);
124 if ( d->is_shutting_down )
125 {
126 if ( !v->paused_for_shutdown )
127 vcpu_pause_nosync(v);
128 v->paused_for_shutdown = 1;
129 v->defer_shutdown = 0;
130 __domain_finalise_shutdown(d);
131 }
133 spin_unlock(&d->shutdown_lock);
134 }
136 struct vcpu *alloc_vcpu(
137 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
138 {
139 struct vcpu *v;
141 BUG_ON((!is_idle_domain(d) || vcpu_id) && d->vcpu[vcpu_id]);
143 if ( (v = alloc_vcpu_struct()) == NULL )
144 return NULL;
146 v->domain = d;
147 v->vcpu_id = vcpu_id;
149 spin_lock_init(&v->virq_lock);
151 tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
153 if ( is_idle_domain(d) )
154 {
155 v->runstate.state = RUNSTATE_running;
156 }
157 else
158 {
159 v->runstate.state = RUNSTATE_offline;
160 v->runstate.state_entry_time = NOW();
161 set_bit(_VPF_down, &v->pause_flags);
162 v->vcpu_info = ((vcpu_id < XEN_LEGACY_MAX_VCPUS)
163 ? (vcpu_info_t *)&shared_info(d, vcpu_info[vcpu_id])
164 : &dummy_vcpu_info);
165 }
167 if ( sched_init_vcpu(v, cpu_id) != 0 )
168 {
169 free_vcpu_struct(v);
170 return NULL;
171 }
173 if ( vcpu_initialise(v) != 0 )
174 {
175 sched_destroy_vcpu(v);
176 free_vcpu_struct(v);
177 return NULL;
178 }
180 d->vcpu[vcpu_id] = v;
181 if ( vcpu_id != 0 )
182 {
183 int prev_id = v->vcpu_id - 1;
184 while ( (prev_id >= 0) && (d->vcpu[prev_id] == NULL) )
185 prev_id--;
186 BUG_ON(prev_id < 0);
187 v->next_in_list = d->vcpu[prev_id]->next_in_list;
188 d->vcpu[prev_id]->next_in_list = v;
189 }
191 /* Must be called after making new vcpu visible to for_each_vcpu(). */
192 vcpu_check_shutdown(v);
194 domain_update_node_affinity(d);
196 return v;
197 }
199 static unsigned int __read_mostly extra_dom0_irqs = 256;
200 static unsigned int __read_mostly extra_domU_irqs = 32;
201 static void __init parse_extra_guest_irqs(const char *s)
202 {
203 if ( isdigit(*s) )
204 extra_domU_irqs = simple_strtoul(s, &s, 0);
205 if ( *s == ',' && isdigit(*++s) )
206 extra_dom0_irqs = simple_strtoul(s, &s, 0);
207 }
208 custom_param("extra_guest_irqs", parse_extra_guest_irqs);
210 struct domain *domain_create(
211 domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
212 {
213 struct domain *d, **pd;
214 enum { INIT_xsm = 1u<<0, INIT_watchdog = 1u<<1, INIT_rangeset = 1u<<2,
215 INIT_evtchn = 1u<<3, INIT_gnttab = 1u<<4, INIT_arch = 1u<<5 };
216 int init_status = 0;
217 int poolid = CPUPOOLID_NONE;
219 if ( (d = alloc_domain_struct()) == NULL )
220 return NULL;
222 d->domain_id = domid;
224 lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
226 if ( xsm_alloc_security_domain(d) != 0 )
227 goto fail;
228 init_status |= INIT_xsm;
230 watchdog_domain_init(d);
231 init_status |= INIT_watchdog;
233 atomic_set(&d->refcnt, 1);
234 spin_lock_init_prof(d, domain_lock);
235 spin_lock_init_prof(d, page_alloc_lock);
236 spin_lock_init(&d->hypercall_deadlock_mutex);
237 INIT_PAGE_LIST_HEAD(&d->page_list);
238 INIT_PAGE_LIST_HEAD(&d->xenpage_list);
240 spin_lock_init(&d->node_affinity_lock);
242 spin_lock_init(&d->shutdown_lock);
243 d->shutdown_code = -1;
245 if ( domcr_flags & DOMCRF_hvm )
246 d->is_hvm = 1;
248 if ( domid == 0 )
249 {
250 d->is_pinned = opt_dom0_vcpus_pin;
251 d->disable_migrate = 1;
252 }
254 rangeset_domain_initialise(d);
255 init_status |= INIT_rangeset;
257 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
258 d->irq_caps = rangeset_new(d, "Interrupts", 0);
259 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
260 goto fail;
262 if ( domcr_flags & DOMCRF_dummy )
263 return d;
265 if ( !is_idle_domain(d) )
266 {
267 if ( xsm_domain_create(d, ssidref) != 0 )
268 goto fail;
270 d->is_paused_by_controller = 1;
271 atomic_inc(&d->pause_count);
273 if ( domid )
274 d->nr_pirqs = nr_irqs_gsi + extra_domU_irqs;
275 else
276 d->nr_pirqs = nr_irqs_gsi + extra_dom0_irqs;
278 d->pirq_to_evtchn = xmalloc_array(u16, d->nr_pirqs);
279 d->pirq_mask = xmalloc_array(
280 unsigned long, BITS_TO_LONGS(d->nr_pirqs));
281 if ( (d->pirq_to_evtchn == NULL) || (d->pirq_mask == NULL) )
282 goto fail;
283 memset(d->pirq_to_evtchn, 0, d->nr_pirqs * sizeof(*d->pirq_to_evtchn));
284 bitmap_zero(d->pirq_mask, d->nr_pirqs);
286 if ( evtchn_init(d) != 0 )
287 goto fail;
288 init_status |= INIT_evtchn;
290 if ( grant_table_create(d) != 0 )
291 goto fail;
292 init_status |= INIT_gnttab;
294 poolid = 0;
295 }
297 if ( arch_domain_create(d, domcr_flags) != 0 )
298 goto fail;
299 init_status |= INIT_arch;
301 if ( cpupool_add_domain(d, poolid) != 0 )
302 goto fail;
304 if ( sched_init_domain(d) != 0 )
305 goto fail;
307 if ( !is_idle_domain(d) )
308 {
309 spin_lock(&domlist_update_lock);
310 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
311 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
312 if ( (*pd)->domain_id > d->domain_id )
313 break;
314 d->next_in_list = *pd;
315 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
316 rcu_assign_pointer(*pd, d);
317 rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
318 spin_unlock(&domlist_update_lock);
319 }
321 return d;
323 fail:
324 d->is_dying = DOMDYING_dead;
325 atomic_set(&d->refcnt, DOMAIN_DESTROYED);
326 if ( init_status & INIT_arch )
327 arch_domain_destroy(d);
328 if ( init_status & INIT_gnttab )
329 grant_table_destroy(d);
330 if ( init_status & INIT_evtchn )
331 {
332 evtchn_destroy(d);
333 evtchn_destroy_final(d);
334 }
335 if ( init_status & INIT_rangeset )
336 rangeset_domain_destroy(d);
337 if ( init_status & INIT_watchdog )
338 watchdog_domain_destroy(d);
339 if ( init_status & INIT_xsm )
340 xsm_free_security_domain(d);
341 xfree(d->pirq_mask);
342 xfree(d->pirq_to_evtchn);
343 free_domain_struct(d);
344 return NULL;
345 }
348 void domain_update_node_affinity(struct domain *d)
349 {
350 cpumask_t cpumask = CPU_MASK_NONE;
351 nodemask_t nodemask = NODE_MASK_NONE;
352 struct vcpu *v;
353 unsigned int node;
355 spin_lock(&d->node_affinity_lock);
357 for_each_vcpu ( d, v )
358 cpus_or(cpumask, cpumask, v->cpu_affinity);
360 for_each_online_node ( node )
361 if ( cpus_intersects(node_to_cpumask(node), cpumask) )
362 node_set(node, nodemask);
364 d->node_affinity = nodemask;
365 spin_unlock(&d->node_affinity_lock);
366 }
369 struct domain *get_domain_by_id(domid_t dom)
370 {
371 struct domain *d;
373 rcu_read_lock(&domlist_read_lock);
375 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
376 d != NULL;
377 d = rcu_dereference(d->next_in_hashbucket) )
378 {
379 if ( d->domain_id == dom )
380 {
381 if ( unlikely(!get_domain(d)) )
382 d = NULL;
383 break;
384 }
385 }
387 rcu_read_unlock(&domlist_read_lock);
389 return d;
390 }
393 struct domain *rcu_lock_domain_by_id(domid_t dom)
394 {
395 struct domain *d;
397 rcu_read_lock(&domlist_read_lock);
399 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
400 d != NULL;
401 d = rcu_dereference(d->next_in_hashbucket) )
402 {
403 if ( d->domain_id == dom )
404 return d;
405 }
407 rcu_read_unlock(&domlist_read_lock);
409 return NULL;
410 }
412 int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d)
413 {
414 if ( dom == DOMID_SELF )
415 {
416 *d = rcu_lock_current_domain();
417 return 0;
418 }
420 if ( (*d = rcu_lock_domain_by_id(dom)) == NULL )
421 return -ESRCH;
423 if ( !IS_PRIV_FOR(current->domain, *d) )
424 {
425 rcu_unlock_domain(*d);
426 return -EPERM;
427 }
429 return 0;
430 }
432 int domain_kill(struct domain *d)
433 {
434 int rc = 0;
436 if ( d == current->domain )
437 return -EINVAL;
439 /* Protected by domctl_lock. */
440 switch ( d->is_dying )
441 {
442 case DOMDYING_alive:
443 domain_pause(d);
444 d->is_dying = DOMDYING_dying;
445 spin_barrier(&d->domain_lock);
446 evtchn_destroy(d);
447 gnttab_release_mappings(d);
448 tmem_destroy(d->tmem);
449 d->tmem = NULL;
450 /* fallthrough */
451 case DOMDYING_dying:
452 rc = domain_relinquish_resources(d);
453 if ( rc != 0 )
454 {
455 BUG_ON(rc != -EAGAIN);
456 break;
457 }
458 d->is_dying = DOMDYING_dead;
459 put_domain(d);
460 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
461 /* fallthrough */
462 case DOMDYING_dead:
463 break;
464 }
466 return rc;
467 }
470 void __domain_crash(struct domain *d)
471 {
472 if ( d->is_shutting_down )
473 {
474 /* Print nothing: the domain is already shutting down. */
475 }
476 else if ( d == current->domain )
477 {
478 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
479 d->domain_id, current->vcpu_id, smp_processor_id());
480 show_execution_state(guest_cpu_user_regs());
481 }
482 else
483 {
484 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
485 d->domain_id, current->domain->domain_id, smp_processor_id());
486 }
488 domain_shutdown(d, SHUTDOWN_crash);
489 }
492 void __domain_crash_synchronous(void)
493 {
494 __domain_crash(current->domain);
496 /*
497 * Flush multicall state before dying if a multicall is in progress.
498 * This shouldn't be necessary, but some architectures are calling
499 * domain_crash_synchronous() when they really shouldn't (i.e., from
500 * within hypercall context).
501 */
502 if ( this_cpu(mc_state).flags != 0 )
503 {
504 dprintk(XENLOG_ERR,
505 "FIXME: synchronous domain crash during a multicall!\n");
506 this_cpu(mc_state).flags = 0;
507 }
509 vcpu_end_shutdown_deferral(current);
511 for ( ; ; )
512 do_softirq();
513 }
516 void domain_shutdown(struct domain *d, u8 reason)
517 {
518 struct vcpu *v;
520 spin_lock(&d->shutdown_lock);
522 if ( d->shutdown_code == -1 )
523 d->shutdown_code = reason;
524 reason = d->shutdown_code;
526 if ( d->domain_id == 0 )
527 dom0_shutdown(reason);
529 if ( d->is_shutting_down )
530 {
531 spin_unlock(&d->shutdown_lock);
532 return;
533 }
535 d->is_shutting_down = 1;
537 smp_mb(); /* set shutdown status /then/ check for per-cpu deferrals */
539 for_each_vcpu ( d, v )
540 {
541 if ( reason == SHUTDOWN_crash )
542 v->defer_shutdown = 0;
543 else if ( v->defer_shutdown )
544 continue;
545 vcpu_pause_nosync(v);
546 v->paused_for_shutdown = 1;
547 }
549 __domain_finalise_shutdown(d);
551 spin_unlock(&d->shutdown_lock);
552 }
554 void domain_resume(struct domain *d)
555 {
556 struct vcpu *v;
558 /*
559 * Some code paths assume that shutdown status does not get reset under
560 * their feet (e.g., some assertions make this assumption).
561 */
562 domain_pause(d);
564 spin_lock(&d->shutdown_lock);
566 d->is_shutting_down = d->is_shut_down = 0;
567 d->shutdown_code = -1;
569 for_each_vcpu ( d, v )
570 {
571 if ( v->paused_for_shutdown )
572 vcpu_unpause(v);
573 v->paused_for_shutdown = 0;
574 }
576 spin_unlock(&d->shutdown_lock);
578 domain_unpause(d);
579 }
581 int vcpu_start_shutdown_deferral(struct vcpu *v)
582 {
583 if ( v->defer_shutdown )
584 return 1;
586 v->defer_shutdown = 1;
587 smp_mb(); /* set deferral status /then/ check for shutdown */
588 if ( unlikely(v->domain->is_shutting_down) )
589 vcpu_check_shutdown(v);
591 return v->defer_shutdown;
592 }
594 void vcpu_end_shutdown_deferral(struct vcpu *v)
595 {
596 v->defer_shutdown = 0;
597 smp_mb(); /* clear deferral status /then/ check for shutdown */
598 if ( unlikely(v->domain->is_shutting_down) )
599 vcpu_check_shutdown(v);
600 }
602 void domain_pause_for_debugger(void)
603 {
604 struct domain *d = current->domain;
605 struct vcpu *v;
607 atomic_inc(&d->pause_count);
608 if ( test_and_set_bool(d->is_paused_by_controller) )
609 domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
611 for_each_vcpu ( d, v )
612 vcpu_sleep_nosync(v);
614 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
615 }
617 /* Complete domain destroy after RCU readers are not holding old references. */
618 static void complete_domain_destroy(struct rcu_head *head)
619 {
620 struct domain *d = container_of(head, struct domain, rcu);
621 struct vcpu *v;
622 int i;
624 for ( i = d->max_vcpus - 1; i >= 0; i-- )
625 {
626 if ( (v = d->vcpu[i]) == NULL )
627 continue;
628 tasklet_kill(&v->continue_hypercall_tasklet);
629 vcpu_destroy(v);
630 sched_destroy_vcpu(v);
631 }
633 grant_table_destroy(d);
635 arch_domain_destroy(d);
637 watchdog_domain_destroy(d);
639 rangeset_domain_destroy(d);
641 cpupool_rm_domain(d);
643 sched_destroy_domain(d);
645 /* Free page used by xen oprofile buffer. */
646 free_xenoprof_pages(d);
648 for ( i = d->max_vcpus - 1; i >= 0; i-- )
649 if ( (v = d->vcpu[i]) != NULL )
650 free_vcpu_struct(v);
652 if ( d->target != NULL )
653 put_domain(d->target);
655 evtchn_destroy_final(d);
657 xfree(d->pirq_mask);
658 xfree(d->pirq_to_evtchn);
660 xsm_free_security_domain(d);
661 free_domain_struct(d);
663 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
664 }
666 /* Release resources belonging to task @p. */
667 void domain_destroy(struct domain *d)
668 {
669 struct domain **pd;
670 atomic_t old, new;
672 BUG_ON(!d->is_dying);
674 /* May be already destroyed, or get_domain() can race us. */
675 _atomic_set(old, 0);
676 _atomic_set(new, DOMAIN_DESTROYED);
677 old = atomic_compareandswap(old, new, &d->refcnt);
678 if ( _atomic_read(old) != 0 )
679 return;
681 /* Delete from task list and task hashtable. */
682 TRACE_1D(TRC_SCHED_DOM_REM, d->domain_id);
683 spin_lock(&domlist_update_lock);
684 pd = &domain_list;
685 while ( *pd != d )
686 pd = &(*pd)->next_in_list;
687 rcu_assign_pointer(*pd, d->next_in_list);
688 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
689 while ( *pd != d )
690 pd = &(*pd)->next_in_hashbucket;
691 rcu_assign_pointer(*pd, d->next_in_hashbucket);
692 spin_unlock(&domlist_update_lock);
694 /* Schedule RCU asynchronous completion of domain destroy. */
695 call_rcu(&d->rcu, complete_domain_destroy);
696 }
698 void vcpu_pause(struct vcpu *v)
699 {
700 ASSERT(v != current);
701 atomic_inc(&v->pause_count);
702 vcpu_sleep_sync(v);
703 }
705 void vcpu_pause_nosync(struct vcpu *v)
706 {
707 atomic_inc(&v->pause_count);
708 vcpu_sleep_nosync(v);
709 }
711 void vcpu_unpause(struct vcpu *v)
712 {
713 if ( atomic_dec_and_test(&v->pause_count) )
714 vcpu_wake(v);
715 }
717 void domain_pause(struct domain *d)
718 {
719 struct vcpu *v;
721 ASSERT(d != current->domain);
723 atomic_inc(&d->pause_count);
725 for_each_vcpu( d, v )
726 vcpu_sleep_sync(v);
727 }
729 void domain_unpause(struct domain *d)
730 {
731 struct vcpu *v;
733 if ( atomic_dec_and_test(&d->pause_count) )
734 for_each_vcpu( d, v )
735 vcpu_wake(v);
736 }
738 void domain_pause_by_systemcontroller(struct domain *d)
739 {
740 domain_pause(d);
741 if ( test_and_set_bool(d->is_paused_by_controller) )
742 domain_unpause(d);
743 }
745 void domain_unpause_by_systemcontroller(struct domain *d)
746 {
747 if ( test_and_clear_bool(d->is_paused_by_controller) )
748 domain_unpause(d);
749 }
751 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
752 {
753 struct vcpu *v = d->vcpu[vcpuid];
755 BUG_ON(v->is_initialised);
757 return arch_set_info_guest(v, ctxt);
758 }
760 void vcpu_reset(struct vcpu *v)
761 {
762 struct domain *d = v->domain;
764 vcpu_pause(v);
765 domain_lock(d);
767 arch_vcpu_reset(v);
769 set_bit(_VPF_down, &v->pause_flags);
771 clear_bit(v->vcpu_id, d->poll_mask);
772 v->poll_evtchn = 0;
774 v->fpu_initialised = 0;
775 v->fpu_dirtied = 0;
776 v->is_initialised = 0;
777 #ifdef VCPU_TRAP_LAST
778 v->async_exception_mask = 0;
779 memset(v->async_exception_state, 0, sizeof(v->async_exception_state));
780 #endif
781 cpus_clear(v->cpu_affinity_tmp);
782 clear_bit(_VPF_blocked, &v->pause_flags);
784 domain_unlock(v->domain);
785 vcpu_unpause(v);
786 }
789 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
790 {
791 struct domain *d = current->domain;
792 struct vcpu *v;
793 struct vcpu_guest_context *ctxt;
794 long rc = 0;
796 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
797 return -EINVAL;
799 if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
800 return -ENOENT;
802 switch ( cmd )
803 {
804 case VCPUOP_initialise:
805 if ( v->vcpu_info == &dummy_vcpu_info )
806 return -EINVAL;
808 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
809 return -ENOMEM;
811 if ( copy_from_guest(ctxt, arg, 1) )
812 {
813 xfree(ctxt);
814 return -EFAULT;
815 }
817 domain_lock(d);
818 rc = -EEXIST;
819 if ( !v->is_initialised )
820 rc = boot_vcpu(d, vcpuid, ctxt);
821 domain_unlock(d);
823 xfree(ctxt);
824 break;
826 case VCPUOP_up:
827 if ( !v->is_initialised )
828 return -EINVAL;
830 if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
831 vcpu_wake(v);
833 break;
835 case VCPUOP_down:
836 if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
837 vcpu_sleep_nosync(v);
838 break;
840 case VCPUOP_is_up:
841 rc = !test_bit(_VPF_down, &v->pause_flags);
842 break;
844 case VCPUOP_get_runstate_info:
845 {
846 struct vcpu_runstate_info runstate;
847 vcpu_runstate_get(v, &runstate);
848 if ( copy_to_guest(arg, &runstate, 1) )
849 rc = -EFAULT;
850 break;
851 }
853 case VCPUOP_set_periodic_timer:
854 {
855 struct vcpu_set_periodic_timer set;
857 if ( copy_from_guest(&set, arg, 1) )
858 return -EFAULT;
860 if ( set.period_ns < MILLISECS(1) )
861 return -EINVAL;
863 v->periodic_period = set.period_ns;
864 vcpu_force_reschedule(v);
866 break;
867 }
869 case VCPUOP_stop_periodic_timer:
870 v->periodic_period = 0;
871 vcpu_force_reschedule(v);
872 break;
874 case VCPUOP_set_singleshot_timer:
875 {
876 struct vcpu_set_singleshot_timer set;
878 if ( v != current )
879 return -EINVAL;
881 if ( copy_from_guest(&set, arg, 1) )
882 return -EFAULT;
884 if ( (set.flags & VCPU_SSHOTTMR_future) &&
885 (set.timeout_abs_ns < NOW()) )
886 return -ETIME;
888 migrate_timer(&v->singleshot_timer, smp_processor_id());
889 set_timer(&v->singleshot_timer, set.timeout_abs_ns);
891 break;
892 }
894 case VCPUOP_stop_singleshot_timer:
895 if ( v != current )
896 return -EINVAL;
898 stop_timer(&v->singleshot_timer);
900 break;
902 #ifdef VCPU_TRAP_NMI
903 case VCPUOP_send_nmi:
904 if ( !guest_handle_is_null(arg) )
905 return -EINVAL;
907 if ( !test_and_set_bool(v->nmi_pending) )
908 vcpu_kick(v);
910 break;
911 #endif
913 default:
914 rc = arch_do_vcpu_op(cmd, v, arg);
915 break;
916 }
918 return rc;
919 }
921 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
922 {
923 if ( type > MAX_VMASST_TYPE )
924 return -EINVAL;
926 switch ( cmd )
927 {
928 case VMASST_CMD_enable:
929 set_bit(type, &p->vm_assist);
930 return 0;
931 case VMASST_CMD_disable:
932 clear_bit(type, &p->vm_assist);
933 return 0;
934 }
936 return -ENOSYS;
937 }
939 struct migrate_info {
940 long (*func)(void *data);
941 void *data;
942 struct vcpu *vcpu;
943 unsigned int cpu;
944 unsigned int nest;
945 };
947 static DEFINE_PER_CPU(struct migrate_info *, continue_info);
949 static void continue_hypercall_tasklet_handler(unsigned long _info)
950 {
951 struct migrate_info *info = (struct migrate_info *)_info;
952 struct vcpu *v = info->vcpu;
954 /* Wait for vcpu to sleep so that we can access its register state. */
955 vcpu_sleep_sync(v);
957 this_cpu(continue_info) = info;
958 return_reg(v) = (info->cpu == smp_processor_id())
959 ? info->func(info->data) : -EINVAL;
960 this_cpu(continue_info) = NULL;
962 if ( info->nest-- == 0 )
963 {
964 xfree(info);
965 vcpu_unpause(v);
966 put_domain(v->domain);
967 }
968 }
970 int continue_hypercall_on_cpu(
971 unsigned int cpu, long (*func)(void *data), void *data)
972 {
973 struct migrate_info *info;
975 if ( (cpu >= NR_CPUS) || !cpu_online(cpu) )
976 return -EINVAL;
978 info = this_cpu(continue_info);
979 if ( info == NULL )
980 {
981 struct vcpu *curr = current;
983 info = xmalloc(struct migrate_info);
984 if ( info == NULL )
985 return -ENOMEM;
987 info->vcpu = curr;
988 info->nest = 0;
990 tasklet_kill(
991 &curr->continue_hypercall_tasklet);
992 tasklet_init(
993 &curr->continue_hypercall_tasklet,
994 continue_hypercall_tasklet_handler,
995 (unsigned long)info);
997 get_knownalive_domain(curr->domain);
998 vcpu_pause_nosync(curr);
999 }
1000 else
1002 BUG_ON(info->nest != 0);
1003 info->nest++;
1006 info->func = func;
1007 info->data = data;
1008 info->cpu = cpu;
1010 tasklet_schedule_on_cpu(&info->vcpu->continue_hypercall_tasklet, cpu);
1012 /* Dummy return value will be overwritten by tasklet. */
1013 return 0;
1016 /*
1017 * Local variables:
1018 * mode: C
1019 * c-set-style: "BSD"
1020 * c-basic-offset: 4
1021 * tab-width: 4
1022 * indent-tabs-mode: nil
1023 * End:
1024 */