debuggers.hg

view xen/common/domain.c @ 22676:e8acb9753ff1

Use bool_t for various boolean variables

... decreasing cache footprint. As a prerequisite this requires making
cmdline_parse() a little more flexible.

Also remove a few variables altogether, and adjust sections
annotations for several others.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Keir Fraser <keir@xen.org>
author Keir Fraser <keir@xen.org>
date Fri Dec 24 10:10:45 2010 +0000 (2010-12-24)
parents 92bc47c81fdc
children 700ac6445812
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 <xen/wait.h>
31 #include <acpi/cpufreq/cpufreq.h>
32 #include <asm/debugger.h>
33 #include <public/sched.h>
34 #include <public/sysctl.h>
35 #include <public/vcpu.h>
36 #include <xsm/xsm.h>
37 #include <xen/trace.h>
38 #include <xen/tmem.h>
40 /* Linux config option: propageted to domain0 */
41 /* xen_processor_pmbits: xen control Cx, Px, ... */
42 unsigned int xen_processor_pmbits = XEN_PROCESSOR_PM_PX;
44 /* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */
45 static bool_t opt_dom0_vcpus_pin;
46 boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
48 /* set xen as default cpufreq */
49 enum cpufreq_controller cpufreq_controller = FREQCTL_xen;
51 static void __init setup_cpufreq_option(char *str)
52 {
53 char *arg;
55 if ( !strcmp(str, "dom0-kernel") )
56 {
57 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
58 cpufreq_controller = FREQCTL_dom0_kernel;
59 opt_dom0_vcpus_pin = 1;
60 return;
61 }
63 if ( !strcmp(str, "none") )
64 {
65 xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
66 cpufreq_controller = FREQCTL_none;
67 return;
68 }
70 if ( (arg = strpbrk(str, ",:")) != NULL )
71 *arg++ = '\0';
73 if ( !strcmp(str, "xen") )
74 if ( arg && *arg )
75 cpufreq_cmdline_parse(arg);
76 }
77 custom_param("cpufreq", setup_cpufreq_option);
79 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
80 DEFINE_SPINLOCK(domlist_update_lock);
81 DEFINE_RCU_READ_LOCK(domlist_read_lock);
83 #define DOMAIN_HASH_SIZE 256
84 #define DOMAIN_HASH(_id) ((int)(_id)&(DOMAIN_HASH_SIZE-1))
85 static struct domain *domain_hash[DOMAIN_HASH_SIZE];
86 struct domain *domain_list;
88 struct domain *dom0;
90 struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
92 vcpu_info_t dummy_vcpu_info;
94 int current_domain_id(void)
95 {
96 return current->domain->domain_id;
97 }
99 static void __domain_finalise_shutdown(struct domain *d)
100 {
101 struct vcpu *v;
103 BUG_ON(!spin_is_locked(&d->shutdown_lock));
105 if ( d->is_shut_down )
106 return;
108 for_each_vcpu ( d, v )
109 if ( !v->paused_for_shutdown )
110 return;
112 d->is_shut_down = 1;
113 if ( (d->shutdown_code == SHUTDOWN_suspend) && d->suspend_evtchn )
114 evtchn_send(d, d->suspend_evtchn);
115 else
116 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
117 }
119 static void vcpu_check_shutdown(struct vcpu *v)
120 {
121 struct domain *d = v->domain;
123 spin_lock(&d->shutdown_lock);
125 if ( d->is_shutting_down )
126 {
127 if ( !v->paused_for_shutdown )
128 vcpu_pause_nosync(v);
129 v->paused_for_shutdown = 1;
130 v->defer_shutdown = 0;
131 __domain_finalise_shutdown(d);
132 }
134 spin_unlock(&d->shutdown_lock);
135 }
137 struct vcpu *alloc_vcpu(
138 struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
139 {
140 struct vcpu *v;
142 BUG_ON((!is_idle_domain(d) || vcpu_id) && d->vcpu[vcpu_id]);
144 if ( (v = alloc_vcpu_struct()) == NULL )
145 return NULL;
147 v->domain = d;
148 v->vcpu_id = vcpu_id;
150 spin_lock_init(&v->virq_lock);
152 tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
154 if ( is_idle_domain(d) )
155 {
156 v->runstate.state = RUNSTATE_running;
157 }
158 else
159 {
160 v->runstate.state = RUNSTATE_offline;
161 v->runstate.state_entry_time = NOW();
162 set_bit(_VPF_down, &v->pause_flags);
163 v->vcpu_info = ((vcpu_id < XEN_LEGACY_MAX_VCPUS)
164 ? (vcpu_info_t *)&shared_info(d, vcpu_info[vcpu_id])
165 : &dummy_vcpu_info);
166 init_waitqueue_vcpu(v);
167 }
169 if ( sched_init_vcpu(v, cpu_id) != 0 )
170 {
171 destroy_waitqueue_vcpu(v);
172 free_vcpu_struct(v);
173 return NULL;
174 }
176 if ( vcpu_initialise(v) != 0 )
177 {
178 sched_destroy_vcpu(v);
179 destroy_waitqueue_vcpu(v);
180 free_vcpu_struct(v);
181 return NULL;
182 }
184 d->vcpu[vcpu_id] = v;
185 if ( vcpu_id != 0 )
186 {
187 int prev_id = v->vcpu_id - 1;
188 while ( (prev_id >= 0) && (d->vcpu[prev_id] == NULL) )
189 prev_id--;
190 BUG_ON(prev_id < 0);
191 v->next_in_list = d->vcpu[prev_id]->next_in_list;
192 d->vcpu[prev_id]->next_in_list = v;
193 }
195 /* Must be called after making new vcpu visible to for_each_vcpu(). */
196 vcpu_check_shutdown(v);
198 domain_update_node_affinity(d);
200 return v;
201 }
203 static unsigned int __read_mostly extra_dom0_irqs = 256;
204 static unsigned int __read_mostly extra_domU_irqs = 32;
205 static void __init parse_extra_guest_irqs(const char *s)
206 {
207 if ( isdigit(*s) )
208 extra_domU_irqs = simple_strtoul(s, &s, 0);
209 if ( *s == ',' && isdigit(*++s) )
210 extra_dom0_irqs = simple_strtoul(s, &s, 0);
211 }
212 custom_param("extra_guest_irqs", parse_extra_guest_irqs);
214 struct domain *domain_create(
215 domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
216 {
217 struct domain *d, **pd;
218 enum { INIT_xsm = 1u<<0, INIT_watchdog = 1u<<1, INIT_rangeset = 1u<<2,
219 INIT_evtchn = 1u<<3, INIT_gnttab = 1u<<4, INIT_arch = 1u<<5 };
220 int init_status = 0;
221 int poolid = CPUPOOLID_NONE;
223 if ( (d = alloc_domain_struct()) == NULL )
224 return NULL;
226 d->domain_id = domid;
228 lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
230 if ( xsm_alloc_security_domain(d) != 0 )
231 goto fail;
232 init_status |= INIT_xsm;
234 watchdog_domain_init(d);
235 init_status |= INIT_watchdog;
237 atomic_set(&d->refcnt, 1);
238 spin_lock_init_prof(d, domain_lock);
239 spin_lock_init_prof(d, page_alloc_lock);
240 spin_lock_init(&d->hypercall_deadlock_mutex);
241 INIT_PAGE_LIST_HEAD(&d->page_list);
242 INIT_PAGE_LIST_HEAD(&d->xenpage_list);
244 spin_lock_init(&d->node_affinity_lock);
246 spin_lock_init(&d->shutdown_lock);
247 d->shutdown_code = -1;
249 if ( domcr_flags & DOMCRF_hvm )
250 d->is_hvm = 1;
252 if ( domid == 0 )
253 {
254 d->is_pinned = opt_dom0_vcpus_pin;
255 d->disable_migrate = 1;
256 }
258 rangeset_domain_initialise(d);
259 init_status |= INIT_rangeset;
261 d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
262 d->irq_caps = rangeset_new(d, "Interrupts", 0);
263 if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
264 goto fail;
266 if ( domcr_flags & DOMCRF_dummy )
267 return d;
269 if ( !is_idle_domain(d) )
270 {
271 if ( xsm_domain_create(d, ssidref) != 0 )
272 goto fail;
274 d->is_paused_by_controller = 1;
275 atomic_inc(&d->pause_count);
277 if ( domid )
278 d->nr_pirqs = nr_irqs_gsi + extra_domU_irqs;
279 else
280 d->nr_pirqs = nr_irqs_gsi + extra_dom0_irqs;
281 if ( d->nr_pirqs > nr_irqs )
282 d->nr_pirqs = nr_irqs;
284 d->pirq_to_evtchn = xmalloc_array(u16, d->nr_pirqs);
285 d->pirq_mask = xmalloc_array(
286 unsigned long, BITS_TO_LONGS(d->nr_pirqs));
287 if ( (d->pirq_to_evtchn == NULL) || (d->pirq_mask == NULL) )
288 goto fail;
289 memset(d->pirq_to_evtchn, 0, d->nr_pirqs * sizeof(*d->pirq_to_evtchn));
290 bitmap_zero(d->pirq_mask, d->nr_pirqs);
292 if ( evtchn_init(d) != 0 )
293 goto fail;
294 init_status |= INIT_evtchn;
296 if ( grant_table_create(d) != 0 )
297 goto fail;
298 init_status |= INIT_gnttab;
300 poolid = 0;
301 }
303 if ( arch_domain_create(d, domcr_flags) != 0 )
304 goto fail;
305 init_status |= INIT_arch;
307 if ( cpupool_add_domain(d, poolid) != 0 )
308 goto fail;
310 if ( sched_init_domain(d) != 0 )
311 goto fail;
313 if ( !is_idle_domain(d) )
314 {
315 spin_lock(&domlist_update_lock);
316 pd = &domain_list; /* NB. domain_list maintained in order of domid. */
317 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list )
318 if ( (*pd)->domain_id > d->domain_id )
319 break;
320 d->next_in_list = *pd;
321 d->next_in_hashbucket = domain_hash[DOMAIN_HASH(domid)];
322 rcu_assign_pointer(*pd, d);
323 rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d);
324 spin_unlock(&domlist_update_lock);
325 }
327 return d;
329 fail:
330 d->is_dying = DOMDYING_dead;
331 atomic_set(&d->refcnt, DOMAIN_DESTROYED);
332 if ( init_status & INIT_arch )
333 arch_domain_destroy(d);
334 if ( init_status & INIT_gnttab )
335 grant_table_destroy(d);
336 if ( init_status & INIT_evtchn )
337 {
338 evtchn_destroy(d);
339 evtchn_destroy_final(d);
340 }
341 if ( init_status & INIT_rangeset )
342 rangeset_domain_destroy(d);
343 if ( init_status & INIT_watchdog )
344 watchdog_domain_destroy(d);
345 if ( init_status & INIT_xsm )
346 xsm_free_security_domain(d);
347 xfree(d->pirq_mask);
348 xfree(d->pirq_to_evtchn);
349 free_domain_struct(d);
350 return NULL;
351 }
354 void domain_update_node_affinity(struct domain *d)
355 {
356 cpumask_t cpumask = CPU_MASK_NONE;
357 nodemask_t nodemask = NODE_MASK_NONE;
358 struct vcpu *v;
359 unsigned int node;
361 spin_lock(&d->node_affinity_lock);
363 for_each_vcpu ( d, v )
364 cpus_or(cpumask, cpumask, v->cpu_affinity);
366 for_each_online_node ( node )
367 if ( cpus_intersects(node_to_cpumask(node), cpumask) )
368 node_set(node, nodemask);
370 d->node_affinity = nodemask;
371 spin_unlock(&d->node_affinity_lock);
372 }
375 struct domain *get_domain_by_id(domid_t dom)
376 {
377 struct domain *d;
379 rcu_read_lock(&domlist_read_lock);
381 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
382 d != NULL;
383 d = rcu_dereference(d->next_in_hashbucket) )
384 {
385 if ( d->domain_id == dom )
386 {
387 if ( unlikely(!get_domain(d)) )
388 d = NULL;
389 break;
390 }
391 }
393 rcu_read_unlock(&domlist_read_lock);
395 return d;
396 }
399 struct domain *rcu_lock_domain_by_id(domid_t dom)
400 {
401 struct domain *d = NULL;
403 rcu_read_lock(&domlist_read_lock);
405 for ( d = rcu_dereference(domain_hash[DOMAIN_HASH(dom)]);
406 d != NULL;
407 d = rcu_dereference(d->next_in_hashbucket) )
408 {
409 if ( d->domain_id == dom )
410 {
411 rcu_lock_domain(d);
412 break;
413 }
414 }
416 rcu_read_unlock(&domlist_read_lock);
418 return d;
419 }
421 int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d)
422 {
423 if ( dom == DOMID_SELF )
424 {
425 *d = rcu_lock_current_domain();
426 return 0;
427 }
429 if ( (*d = rcu_lock_domain_by_id(dom)) == NULL )
430 return -ESRCH;
432 if ( !IS_PRIV_FOR(current->domain, *d) )
433 {
434 rcu_unlock_domain(*d);
435 return -EPERM;
436 }
438 return 0;
439 }
441 int domain_kill(struct domain *d)
442 {
443 int rc = 0;
445 if ( d == current->domain )
446 return -EINVAL;
448 /* Protected by domctl_lock. */
449 switch ( d->is_dying )
450 {
451 case DOMDYING_alive:
452 domain_pause(d);
453 d->is_dying = DOMDYING_dying;
454 spin_barrier(&d->domain_lock);
455 evtchn_destroy(d);
456 gnttab_release_mappings(d);
457 tmem_destroy(d->tmem);
458 d->tmem = NULL;
459 /* fallthrough */
460 case DOMDYING_dying:
461 rc = domain_relinquish_resources(d);
462 if ( rc != 0 )
463 {
464 BUG_ON(rc != -EAGAIN);
465 break;
466 }
467 d->is_dying = DOMDYING_dead;
468 put_domain(d);
469 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
470 /* fallthrough */
471 case DOMDYING_dead:
472 break;
473 }
475 return rc;
476 }
479 void __domain_crash(struct domain *d)
480 {
481 if ( d->is_shutting_down )
482 {
483 /* Print nothing: the domain is already shutting down. */
484 }
485 else if ( d == current->domain )
486 {
487 printk("Domain %d (vcpu#%d) crashed on cpu#%d:\n",
488 d->domain_id, current->vcpu_id, smp_processor_id());
489 show_execution_state(guest_cpu_user_regs());
490 }
491 else
492 {
493 printk("Domain %d reported crashed by domain %d on cpu#%d:\n",
494 d->domain_id, current->domain->domain_id, smp_processor_id());
495 }
497 domain_shutdown(d, SHUTDOWN_crash);
498 }
501 void __domain_crash_synchronous(void)
502 {
503 __domain_crash(current->domain);
505 vcpu_end_shutdown_deferral(current);
507 for ( ; ; )
508 do_softirq();
509 }
512 void domain_shutdown(struct domain *d, u8 reason)
513 {
514 struct vcpu *v;
516 spin_lock(&d->shutdown_lock);
518 if ( d->shutdown_code == -1 )
519 d->shutdown_code = reason;
520 reason = d->shutdown_code;
522 if ( d->domain_id == 0 )
523 dom0_shutdown(reason);
525 if ( d->is_shutting_down )
526 {
527 spin_unlock(&d->shutdown_lock);
528 return;
529 }
531 d->is_shutting_down = 1;
533 smp_mb(); /* set shutdown status /then/ check for per-cpu deferrals */
535 for_each_vcpu ( d, v )
536 {
537 if ( reason == SHUTDOWN_crash )
538 v->defer_shutdown = 0;
539 else if ( v->defer_shutdown )
540 continue;
541 vcpu_pause_nosync(v);
542 v->paused_for_shutdown = 1;
543 }
545 __domain_finalise_shutdown(d);
547 spin_unlock(&d->shutdown_lock);
548 }
550 void domain_resume(struct domain *d)
551 {
552 struct vcpu *v;
554 /*
555 * Some code paths assume that shutdown status does not get reset under
556 * their feet (e.g., some assertions make this assumption).
557 */
558 domain_pause(d);
560 spin_lock(&d->shutdown_lock);
562 d->is_shutting_down = d->is_shut_down = 0;
563 d->shutdown_code = -1;
565 for_each_vcpu ( d, v )
566 {
567 if ( v->paused_for_shutdown )
568 vcpu_unpause(v);
569 v->paused_for_shutdown = 0;
570 }
572 spin_unlock(&d->shutdown_lock);
574 domain_unpause(d);
575 }
577 int vcpu_start_shutdown_deferral(struct vcpu *v)
578 {
579 if ( v->defer_shutdown )
580 return 1;
582 v->defer_shutdown = 1;
583 smp_mb(); /* set deferral status /then/ check for shutdown */
584 if ( unlikely(v->domain->is_shutting_down) )
585 vcpu_check_shutdown(v);
587 return v->defer_shutdown;
588 }
590 void vcpu_end_shutdown_deferral(struct vcpu *v)
591 {
592 v->defer_shutdown = 0;
593 smp_mb(); /* clear deferral status /then/ check for shutdown */
594 if ( unlikely(v->domain->is_shutting_down) )
595 vcpu_check_shutdown(v);
596 }
598 void domain_pause_for_debugger(void)
599 {
600 struct domain *d = current->domain;
601 struct vcpu *v;
603 atomic_inc(&d->pause_count);
604 if ( test_and_set_bool(d->is_paused_by_controller) )
605 domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
607 for_each_vcpu ( d, v )
608 vcpu_sleep_nosync(v);
610 send_guest_global_virq(dom0, VIRQ_DEBUGGER);
611 }
613 /* Complete domain destroy after RCU readers are not holding old references. */
614 static void complete_domain_destroy(struct rcu_head *head)
615 {
616 struct domain *d = container_of(head, struct domain, rcu);
617 struct vcpu *v;
618 int i;
620 for ( i = d->max_vcpus - 1; i >= 0; i-- )
621 {
622 if ( (v = d->vcpu[i]) == NULL )
623 continue;
624 tasklet_kill(&v->continue_hypercall_tasklet);
625 vcpu_destroy(v);
626 sched_destroy_vcpu(v);
627 destroy_waitqueue_vcpu(v);
628 }
630 grant_table_destroy(d);
632 arch_domain_destroy(d);
634 watchdog_domain_destroy(d);
636 rangeset_domain_destroy(d);
638 cpupool_rm_domain(d);
640 sched_destroy_domain(d);
642 /* Free page used by xen oprofile buffer. */
643 free_xenoprof_pages(d);
645 for ( i = d->max_vcpus - 1; i >= 0; i-- )
646 if ( (v = d->vcpu[i]) != NULL )
647 free_vcpu_struct(v);
649 if ( d->target != NULL )
650 put_domain(d->target);
652 evtchn_destroy_final(d);
654 xfree(d->pirq_mask);
655 xfree(d->pirq_to_evtchn);
657 xsm_free_security_domain(d);
658 free_domain_struct(d);
660 send_guest_global_virq(dom0, VIRQ_DOM_EXC);
661 }
663 /* Release resources belonging to task @p. */
664 void domain_destroy(struct domain *d)
665 {
666 struct domain **pd;
667 atomic_t old, new;
669 BUG_ON(!d->is_dying);
671 /* May be already destroyed, or get_domain() can race us. */
672 _atomic_set(old, 0);
673 _atomic_set(new, DOMAIN_DESTROYED);
674 old = atomic_compareandswap(old, new, &d->refcnt);
675 if ( _atomic_read(old) != 0 )
676 return;
678 /* Delete from task list and task hashtable. */
679 TRACE_1D(TRC_SCHED_DOM_REM, d->domain_id);
680 spin_lock(&domlist_update_lock);
681 pd = &domain_list;
682 while ( *pd != d )
683 pd = &(*pd)->next_in_list;
684 rcu_assign_pointer(*pd, d->next_in_list);
685 pd = &domain_hash[DOMAIN_HASH(d->domain_id)];
686 while ( *pd != d )
687 pd = &(*pd)->next_in_hashbucket;
688 rcu_assign_pointer(*pd, d->next_in_hashbucket);
689 spin_unlock(&domlist_update_lock);
691 /* Schedule RCU asynchronous completion of domain destroy. */
692 call_rcu(&d->rcu, complete_domain_destroy);
693 }
695 void vcpu_pause(struct vcpu *v)
696 {
697 ASSERT(v != current);
698 atomic_inc(&v->pause_count);
699 vcpu_sleep_sync(v);
700 }
702 void vcpu_pause_nosync(struct vcpu *v)
703 {
704 atomic_inc(&v->pause_count);
705 vcpu_sleep_nosync(v);
706 }
708 void vcpu_unpause(struct vcpu *v)
709 {
710 if ( atomic_dec_and_test(&v->pause_count) )
711 vcpu_wake(v);
712 }
714 void domain_pause(struct domain *d)
715 {
716 struct vcpu *v;
718 ASSERT(d != current->domain);
720 atomic_inc(&d->pause_count);
722 for_each_vcpu( d, v )
723 vcpu_sleep_sync(v);
724 }
726 void domain_unpause(struct domain *d)
727 {
728 struct vcpu *v;
730 if ( atomic_dec_and_test(&d->pause_count) )
731 for_each_vcpu( d, v )
732 vcpu_wake(v);
733 }
735 void domain_pause_by_systemcontroller(struct domain *d)
736 {
737 domain_pause(d);
738 if ( test_and_set_bool(d->is_paused_by_controller) )
739 domain_unpause(d);
740 }
742 void domain_unpause_by_systemcontroller(struct domain *d)
743 {
744 if ( test_and_clear_bool(d->is_paused_by_controller) )
745 domain_unpause(d);
746 }
748 int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
749 {
750 struct vcpu *v = d->vcpu[vcpuid];
752 BUG_ON(v->is_initialised);
754 return arch_set_info_guest(v, ctxt);
755 }
757 void vcpu_reset(struct vcpu *v)
758 {
759 struct domain *d = v->domain;
761 vcpu_pause(v);
762 domain_lock(d);
764 arch_vcpu_reset(v);
766 set_bit(_VPF_down, &v->pause_flags);
768 clear_bit(v->vcpu_id, d->poll_mask);
769 v->poll_evtchn = 0;
771 v->fpu_initialised = 0;
772 v->fpu_dirtied = 0;
773 v->is_initialised = 0;
774 #ifdef VCPU_TRAP_LAST
775 v->async_exception_mask = 0;
776 memset(v->async_exception_state, 0, sizeof(v->async_exception_state));
777 #endif
778 cpus_clear(v->cpu_affinity_tmp);
779 clear_bit(_VPF_blocked, &v->pause_flags);
781 domain_unlock(v->domain);
782 vcpu_unpause(v);
783 }
786 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
787 {
788 struct domain *d = current->domain;
789 struct vcpu *v;
790 struct vcpu_guest_context *ctxt;
791 long rc = 0;
793 if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
794 return -EINVAL;
796 if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
797 return -ENOENT;
799 switch ( cmd )
800 {
801 case VCPUOP_initialise:
802 if ( v->vcpu_info == &dummy_vcpu_info )
803 return -EINVAL;
805 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
806 return -ENOMEM;
808 if ( copy_from_guest(ctxt, arg, 1) )
809 {
810 xfree(ctxt);
811 return -EFAULT;
812 }
814 domain_lock(d);
815 rc = -EEXIST;
816 if ( !v->is_initialised )
817 rc = boot_vcpu(d, vcpuid, ctxt);
818 domain_unlock(d);
820 xfree(ctxt);
821 break;
823 case VCPUOP_up:
824 if ( !v->is_initialised )
825 return -EINVAL;
827 if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
828 vcpu_wake(v);
830 break;
832 case VCPUOP_down:
833 if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
834 vcpu_sleep_nosync(v);
835 break;
837 case VCPUOP_is_up:
838 rc = !test_bit(_VPF_down, &v->pause_flags);
839 break;
841 case VCPUOP_get_runstate_info:
842 {
843 struct vcpu_runstate_info runstate;
844 vcpu_runstate_get(v, &runstate);
845 if ( copy_to_guest(arg, &runstate, 1) )
846 rc = -EFAULT;
847 break;
848 }
850 case VCPUOP_set_periodic_timer:
851 {
852 struct vcpu_set_periodic_timer set;
854 if ( copy_from_guest(&set, arg, 1) )
855 return -EFAULT;
857 if ( set.period_ns < MILLISECS(1) )
858 return -EINVAL;
860 v->periodic_period = set.period_ns;
861 vcpu_force_reschedule(v);
863 break;
864 }
866 case VCPUOP_stop_periodic_timer:
867 v->periodic_period = 0;
868 vcpu_force_reschedule(v);
869 break;
871 case VCPUOP_set_singleshot_timer:
872 {
873 struct vcpu_set_singleshot_timer set;
875 if ( v != current )
876 return -EINVAL;
878 if ( copy_from_guest(&set, arg, 1) )
879 return -EFAULT;
881 if ( (set.flags & VCPU_SSHOTTMR_future) &&
882 (set.timeout_abs_ns < NOW()) )
883 return -ETIME;
885 migrate_timer(&v->singleshot_timer, smp_processor_id());
886 set_timer(&v->singleshot_timer, set.timeout_abs_ns);
888 break;
889 }
891 case VCPUOP_stop_singleshot_timer:
892 if ( v != current )
893 return -EINVAL;
895 stop_timer(&v->singleshot_timer);
897 break;
899 #ifdef VCPU_TRAP_NMI
900 case VCPUOP_send_nmi:
901 if ( !guest_handle_is_null(arg) )
902 return -EINVAL;
904 if ( !test_and_set_bool(v->nmi_pending) )
905 vcpu_kick(v);
907 break;
908 #endif
910 default:
911 rc = arch_do_vcpu_op(cmd, v, arg);
912 break;
913 }
915 return rc;
916 }
918 long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
919 {
920 if ( type > MAX_VMASST_TYPE )
921 return -EINVAL;
923 switch ( cmd )
924 {
925 case VMASST_CMD_enable:
926 set_bit(type, &p->vm_assist);
927 return 0;
928 case VMASST_CMD_disable:
929 clear_bit(type, &p->vm_assist);
930 return 0;
931 }
933 return -ENOSYS;
934 }
936 struct migrate_info {
937 long (*func)(void *data);
938 void *data;
939 struct vcpu *vcpu;
940 unsigned int cpu;
941 unsigned int nest;
942 };
944 static DEFINE_PER_CPU(struct migrate_info *, continue_info);
946 static void continue_hypercall_tasklet_handler(unsigned long _info)
947 {
948 struct migrate_info *info = (struct migrate_info *)_info;
949 struct vcpu *v = info->vcpu;
951 /* Wait for vcpu to sleep so that we can access its register state. */
952 vcpu_sleep_sync(v);
954 this_cpu(continue_info) = info;
955 return_reg(v) = (info->cpu == smp_processor_id())
956 ? info->func(info->data) : -EINVAL;
957 this_cpu(continue_info) = NULL;
959 if ( info->nest-- == 0 )
960 {
961 xfree(info);
962 vcpu_unpause(v);
963 put_domain(v->domain);
964 }
965 }
967 int continue_hypercall_on_cpu(
968 unsigned int cpu, long (*func)(void *data), void *data)
969 {
970 struct migrate_info *info;
972 if ( (cpu >= NR_CPUS) || !cpu_online(cpu) )
973 return -EINVAL;
975 info = this_cpu(continue_info);
976 if ( info == NULL )
977 {
978 struct vcpu *curr = current;
980 info = xmalloc(struct migrate_info);
981 if ( info == NULL )
982 return -ENOMEM;
984 info->vcpu = curr;
985 info->nest = 0;
987 tasklet_kill(
988 &curr->continue_hypercall_tasklet);
989 tasklet_init(
990 &curr->continue_hypercall_tasklet,
991 continue_hypercall_tasklet_handler,
992 (unsigned long)info);
994 get_knownalive_domain(curr->domain);
995 vcpu_pause_nosync(curr);
996 }
997 else
998 {
999 BUG_ON(info->nest != 0);
1000 info->nest++;
1003 info->func = func;
1004 info->data = data;
1005 info->cpu = cpu;
1007 tasklet_schedule_on_cpu(&info->vcpu->continue_hypercall_tasklet, cpu);
1009 /* Dummy return value will be overwritten by tasklet. */
1010 return 0;
1013 /*
1014 * Local variables:
1015 * mode: C
1016 * c-set-style: "BSD"
1017 * c-basic-offset: 4
1018 * tab-width: 4
1019 * indent-tabs-mode: nil
1020 * End:
1021 */